[Libreoffice-commits] core.git: include/vcl vcl/inc vcl/Library_vcl.mk vcl/qa vcl/source
Chris Sherlock (via logerrit)
logerrit at kemper.freedesktop.org
Mon Sep 6 10:52:53 UTC 2021
include/vcl/outdev.hxx | 8
include/vcl/vcllayout.hxx | 6
vcl/Library_vcl.mk | 1
vcl/inc/ImplLayoutArgs.hxx | 69 +++++++
vcl/inc/salgdi.hxx | 1
vcl/inc/sallayout.hxx | 62 ------
vcl/qa/cppunit/complextext.cxx | 5
vcl/qa/cppunit/text.cxx | 142 +++++++++++++++
vcl/source/gdi/CommonSalLayout.cxx | 7
vcl/source/gdi/sallayout.cxx | 278 ------------------------------
vcl/source/outdev/font.cxx | 5
vcl/source/outdev/text.cxx | 9
vcl/source/text/ImplLayoutArgs.cxx | 339 +++++++++++++++++++++++++++++++++++++
13 files changed, 585 insertions(+), 347 deletions(-)
New commits:
commit 8381242c2e0bfda1b37e7e82525926c0497c81d4
Author: Chris Sherlock <chris.sherlock79 at gmail.com>
AuthorDate: Sun Mar 7 13:59:04 2021 +1100
Commit: Noel Grandin <noel.grandin at collabora.co.uk>
CommitDate: Mon Sep 6 12:52:14 2021 +0200
vcl: move ImplLayoutArgs to own header and source files
Add unit tests for ImplLayoutArgs. Also add to the vcl::text namespace.
Change-Id: I9fa0943548be8ca17ea3dac104e9cb609337a70e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/121209
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin at collabora.co.uk>
diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index 26376fedc9e2..6bf789793af6 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -89,7 +89,6 @@ class LineInfo;
class AlphaMask;
class FontCharMap;
class SalLayout;
-class ImplLayoutArgs;
class VirtualDevice;
struct SalTwoRect;
class Printer;
@@ -109,6 +108,7 @@ namespace vcl
}
namespace text {
+ class ImplLayoutArgs;
class TextLayoutCache;
}
}
@@ -1226,18 +1226,18 @@ public:
const tools::Long* pLogicDXArray=nullptr, SalLayoutFlags flags = SalLayoutFlags::NONE,
vcl::text::TextLayoutCache const* = nullptr,
const SalLayoutGlyphs* pGlyphs = nullptr) const;
- SAL_DLLPRIVATE ImplLayoutArgs ImplPrepareLayoutArgs( OUString&, const sal_Int32 nIndex, const sal_Int32 nLen,
+ SAL_DLLPRIVATE vcl::text::ImplLayoutArgs ImplPrepareLayoutArgs( OUString&, const sal_Int32 nIndex, const sal_Int32 nLen,
DeviceCoordinate nPixelWidth, const DeviceCoordinate* pPixelDXArray,
SalLayoutFlags flags = SalLayoutFlags::NONE,
vcl::text::TextLayoutCache const* = nullptr) const;
SAL_DLLPRIVATE std::unique_ptr<SalLayout>
ImplGlyphFallbackLayout( std::unique_ptr<SalLayout>,
- ImplLayoutArgs&,
+ vcl::text::ImplLayoutArgs&,
const SalLayoutGlyphs* ) const;
SAL_DLLPRIVATE std::unique_ptr<SalLayout>
getFallbackLayout(
LogicalFontInstance* pLogicalFont, int nFallbackLevel,
- ImplLayoutArgs& rLayoutArgs, const SalLayoutGlyphs* ) const;
+ vcl::text::ImplLayoutArgs& rLayoutArgs, const SalLayoutGlyphs* ) const;
// Enabling/disabling RTL only makes sense for OutputDevices that use a mirroring SalGraphicsLayout
diff --git a/include/vcl/vcllayout.hxx b/include/vcl/vcllayout.hxx
index 670e8aaad0c3..2546b5f72c09 100644
--- a/include/vcl/vcllayout.hxx
+++ b/include/vcl/vcllayout.hxx
@@ -28,7 +28,7 @@
#include <vcl/dllapi.h>
class LogicalFontInstance;
-class ImplLayoutArgs;
+namespace vcl::text { class ImplLayoutArgs; }
class PhysicalFontFace;
class SalGraphics;
class GlyphItem;
@@ -74,8 +74,8 @@ public:
const Point& DrawOffset() const { return maDrawOffset; }
Point GetDrawPosition( const Point& rRelative = Point(0,0) ) const;
- virtual bool LayoutText( ImplLayoutArgs&, const SalLayoutGlyphsImpl* ) = 0; // first step of layouting
- virtual void AdjustLayout( ImplLayoutArgs& ); // adjusting after fallback etc.
+ virtual bool LayoutText( vcl::text::ImplLayoutArgs&, const SalLayoutGlyphsImpl* ) = 0; // first step of layouting
+ virtual void AdjustLayout( vcl::text::ImplLayoutArgs& ); // adjusting after fallback etc.
virtual void InitFont() const {}
virtual void DrawText( SalGraphics& ) const = 0;
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index 05f33b07115d..f9403f25b7e9 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -236,6 +236,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/source/outdev/vclreferencebase \
vcl/source/outdev/nativecontrols \
vcl/source/outdev/map \
+ vcl/source/text/ImplLayoutArgs \
vcl/source/text/TextLayoutCache \
vcl/source/treelist/headbar \
vcl/source/treelist/iconview \
diff --git a/vcl/inc/ImplLayoutArgs.hxx b/vcl/inc/ImplLayoutArgs.hxx
new file mode 100644
index 000000000000..865470b7897a
--- /dev/null
+++ b/vcl/inc/ImplLayoutArgs.hxx
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "sallayout.hxx"
+
+namespace vcl::text
+{
+class VCL_DLLPUBLIC ImplLayoutArgs
+{
+public:
+ // string related inputs
+ LanguageTag maLanguageTag;
+ SalLayoutFlags mnFlags;
+ const OUString& mrStr;
+ int mnMinCharPos;
+ int mnEndCharPos;
+
+ // performance hack
+ vcl::text::TextLayoutCache const* m_pTextLayoutCache;
+
+ // positioning related inputs
+ const DeviceCoordinate* mpDXArray; // in pixel units
+ DeviceCoordinate mnLayoutWidth; // in pixel units
+ Degree10 mnOrientation; // in 0-3600 system
+
+ // data for bidi and glyph+script fallback
+ ImplLayoutRuns maRuns;
+ ImplLayoutRuns maFallbackRuns;
+
+ ImplLayoutArgs(OUString const& rStr, int nMinCharPos, int nEndCharPos, SalLayoutFlags nFlags,
+ LanguageTag const& rLanguageTag, vcl::text::TextLayoutCache const* pLayoutCache);
+
+ void SetLayoutWidth(DeviceCoordinate nWidth);
+ void SetDXArray(const DeviceCoordinate* 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);
+ // methods used by BiDi and glyph fallback
+ bool HasFallbackRun() const;
+ bool PrepareFallback(const SalLayoutGlyphsImpl* pGlyphsImpl);
+
+private:
+ void AddRun(int nMinCharPos, int nEndCharPos, bool bRTL);
+};
+}
+
+// For nice SAL_INFO logging of ImplLayoutArgs values
+std::ostream& operator<<(std::ostream& s, vcl::text::ImplLayoutArgs const& rArgs);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx
index 9c99fcd5fa0b..65e56367d2f2 100644
--- a/vcl/inc/salgdi.hxx
+++ b/vcl/inc/salgdi.hxx
@@ -40,7 +40,6 @@ class FontSelectPattern;
class FontAttributes;
class PhysicalFontFace;
class SalLayout;
-class ImplLayoutArgs;
namespace tools { class Rectangle; }
class FontSubsetInfo;
class OutputDevice;
diff --git a/vcl/inc/sallayout.hxx b/vcl/inc/sallayout.hxx
index b2bdcc2d4cb0..594202b23239 100644
--- a/vcl/inc/sallayout.hxx
+++ b/vcl/inc/sallayout.hxx
@@ -73,56 +73,6 @@ public:
bool PosIsInAnyRun( int nCharPos ) const;
};
-class VCL_DLLPUBLIC ImplLayoutArgs
-{
-public:
- // string related inputs
- LanguageTag maLanguageTag;
- SalLayoutFlags mnFlags;
- const OUString& mrStr;
- int mnMinCharPos;
- int mnEndCharPos;
-
- // performance hack
- vcl::text::TextLayoutCache const* m_pTextLayoutCache;
-
- // positioning related inputs
- const DeviceCoordinate* mpDXArray; // in pixel units
- DeviceCoordinate mnLayoutWidth; // in pixel units
- Degree10 mnOrientation; // in 0-3600 system
-
- // data for bidi and glyph+script fallback
- ImplLayoutRuns maRuns;
- ImplLayoutRuns maFallbackRuns;
-
- ImplLayoutArgs( const OUString& rStr,
- int nMinCharPos, int nEndCharPos, SalLayoutFlags nFlags,
- const LanguageTag& rLanguageTag,
- vcl::text::TextLayoutCache const* pLayoutCache);
-
- void SetLayoutWidth( DeviceCoordinate nWidth ) { mnLayoutWidth = nWidth; }
- void SetDXArray( const DeviceCoordinate* pDXArray ) { mpDXArray = pDXArray; }
- void SetOrientation( Degree10 nOrientation ) { mnOrientation = nOrientation; }
-
- void ResetPos()
- { maRuns.ResetPos(); }
- bool GetNextPos( int* nCharPos, bool* bRTL )
- { return maRuns.GetNextPos( nCharPos, bRTL ); }
- bool GetNextRun( int* nMinRunPos, int* nEndRunPos, bool* bRTL );
- void AddFallbackRun( int nMinRunPos, int nEndRunPos, bool bRTL )
- { maFallbackRuns.AddRun( nMinRunPos, nEndRunPos, bRTL ); }
- // methods used by BiDi and glyph fallback
- bool HasFallbackRun() const
- { return !maFallbackRuns.IsEmpty(); }
- bool PrepareFallback(const SalLayoutGlyphsImpl* pGlyphsImpl);
-
-private:
- void AddRun( int nMinCharPos, int nEndCharPos, bool bRTL );
-};
-
-// For nice SAL_INFO logging of ImplLayoutArgs values
-std::ostream &operator <<(std::ostream& s, ImplLayoutArgs const &rArgs);
-
class MultiSalLayout final : public SalLayout
{
public:
@@ -142,8 +92,8 @@ public:
void AddFallback(std::unique_ptr<SalLayout> pFallbackLayout, ImplLayoutRuns const &);
// give up ownership of the initial pBaseLayout taken by the ctor
std::unique_ptr<SalLayout> ReleaseBaseLayout();
- bool LayoutText(ImplLayoutArgs&, const SalLayoutGlyphsImpl*) override;
- void AdjustLayout(ImplLayoutArgs&) override;
+ bool LayoutText(vcl::text::ImplLayoutArgs&, const SalLayoutGlyphsImpl*) override;
+ void AdjustLayout(vcl::text::ImplLayoutArgs&) override;
void InitFont() const override;
void SetIncomplete(bool bIncomplete);
@@ -163,14 +113,14 @@ private:
class VCL_DLLPUBLIC GenericSalLayout : public SalLayout
{
- friend void MultiSalLayout::AdjustLayout(ImplLayoutArgs&);
+ friend void MultiSalLayout::AdjustLayout(vcl::text::ImplLayoutArgs&);
public:
GenericSalLayout(LogicalFontInstance&);
~GenericSalLayout() override;
- void AdjustLayout(ImplLayoutArgs&) final override;
- bool LayoutText(ImplLayoutArgs&, const SalLayoutGlyphsImpl*) final override;
+ void AdjustLayout(vcl::text::ImplLayoutArgs&) final override;
+ bool LayoutText(vcl::text::ImplLayoutArgs&, const SalLayoutGlyphsImpl*) final override;
void DrawText(SalGraphics&) const final override;
static std::shared_ptr<vcl::text::TextLayoutCache> CreateTextLayoutCache(OUString const&);
SalLayoutGlyphs GetGlyphs() const final override;
@@ -208,7 +158,7 @@ private:
void GetCharWidths(std::vector<DeviceCoordinate>& rCharWidths) const;
- void SetNeedFallback(ImplLayoutArgs&, sal_Int32, bool);
+ void SetNeedFallback(vcl::text::ImplLayoutArgs&, sal_Int32, bool);
bool HasVerticalAlternate(sal_UCS4 aChar, sal_UCS4 aNextChar);
diff --git a/vcl/qa/cppunit/complextext.cxx b/vcl/qa/cppunit/complextext.cxx
index 77a98aa7afdb..5b16b4d06e74 100644
--- a/vcl/qa/cppunit/complextext.cxx
+++ b/vcl/qa/cppunit/complextext.cxx
@@ -25,6 +25,9 @@ static std::ostream& operator<<(std::ostream& rStream, const std::vector<tools::
#include <sallayout.hxx>
#include <salgdi.hxx>
+
+#include <ImplLayoutArgs.hxx>
+
#if HAVE_MORE_FONTS
static std::ostream& operator<<(std::ostream& rStream, const std::vector<tools::Long>& rVec)
{
@@ -129,7 +132,7 @@ void VclComplexTextTest::testKashida()
CPPUNIT_ASSERT(aGlyphs.Impl(0) != nullptr);
// Now lay it out using the cached glyph list.
- ImplLayoutArgs aLayoutArgs(aText, 0, aText.getLength(), SalLayoutFlags::NONE,
+ vcl::text::ImplLayoutArgs aLayoutArgs(aText, 0, aText.getLength(), SalLayoutFlags::NONE,
pOutputDevice->GetFont().GetLanguageTag(), nullptr);
pLayout = pOutputDevice->GetGraphics()->GetTextLayout(0);
CPPUNIT_ASSERT(pLayout->LayoutText(aLayoutArgs, aGlyphs.Impl(0)));
diff --git a/vcl/qa/cppunit/text.cxx b/vcl/qa/cppunit/text.cxx
index 548690674f47..c9f0d36c50c3 100644
--- a/vcl/qa/cppunit/text.cxx
+++ b/vcl/qa/cppunit/text.cxx
@@ -10,6 +10,7 @@
#include <test/bootstrapfixture.hxx>
#include <sal/log.hxx>
#include <tools/stream.hxx>
+#include <i18nlangtag/languagetag.hxx>
#include <vcl/BitmapReadAccess.hxx>
#include <vcl/graphicfilter.hxx>
@@ -17,6 +18,7 @@
#include <vcl/svapp.hxx>
#include <vcl/virdev.hxx>
+#include <ImplLayoutArgs.hxx>
#include <TextLayoutCache.hxx>
#include <salgdi.hxx>
@@ -45,11 +47,19 @@ public:
void testSimpleText();
void testVerticalText();
void testTextLayoutCache();
+ void testImplLayoutArgsBiDiStrong();
+ void testImplLayoutArgsBiDiRtl();
+ void testImplLayoutArgsRightAlign();
+ void testImplLayoutArgs_PrepareFallback_precalculatedglyphs();
CPPUNIT_TEST_SUITE(VclTextTest);
CPPUNIT_TEST(testSimpleText);
CPPUNIT_TEST(testVerticalText);
CPPUNIT_TEST(testTextLayoutCache);
+ CPPUNIT_TEST(testImplLayoutArgsBiDiStrong);
+ CPPUNIT_TEST(testImplLayoutArgsBiDiRtl);
+ CPPUNIT_TEST(testImplLayoutArgsRightAlign);
+ CPPUNIT_TEST(testImplLayoutArgs_PrepareFallback_precalculatedglyphs);
CPPUNIT_TEST_SUITE_END();
};
@@ -397,6 +407,138 @@ void VclTextTest::testTextLayoutCache()
CPPUNIT_ASSERT_EQUAL(51, run2.nEnd);
}
+void VclTextTest::testImplLayoutArgsBiDiStrong()
+{
+ OUString sTestString = u"The quick brown fox\n jumped over the lazy dog"
+ "العاشر";
+ vcl::text::ImplLayoutArgs aArgs(sTestString, 0, sTestString.getLength(),
+ SalLayoutFlags::BiDiStrong, LanguageTag(LANGUAGE_NONE),
+ nullptr);
+
+ int* nMinRunPos = new int(0);
+ int* nEndRunPos = new int(0);
+ bool* pRTL = new bool(false);
+
+ aArgs.GetNextRun(nMinRunPos, nEndRunPos, pRTL);
+ CPPUNIT_ASSERT_EQUAL(0, *nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(19, *nEndRunPos);
+ CPPUNIT_ASSERT(!*pRTL);
+
+ aArgs.GetNextRun(nMinRunPos, nEndRunPos, pRTL);
+ CPPUNIT_ASSERT_EQUAL(20, *nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(51, *nEndRunPos);
+ CPPUNIT_ASSERT(!*pRTL);
+
+ aArgs.GetNextRun(nMinRunPos, nEndRunPos, pRTL);
+ CPPUNIT_ASSERT_EQUAL(20, *nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(51, *nEndRunPos);
+}
+
+void VclTextTest::testImplLayoutArgsBiDiRtl()
+{
+ OUString sTestString = u"The quick brown fox\n jumped over the lazy dog"
+ "العاشر";
+ vcl::text::ImplLayoutArgs aArgs(sTestString, 0, sTestString.getLength(),
+ SalLayoutFlags::BiDiRtl, LanguageTag(LANGUAGE_NONE), nullptr);
+
+ int* nMinRunPos = new int(0);
+ int* nEndRunPos = new int(0);
+ bool* pRTL = new bool(false);
+
+ aArgs.GetNextRun(nMinRunPos, nEndRunPos, pRTL);
+ CPPUNIT_ASSERT_EQUAL(45, *nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(51, *nEndRunPos);
+ CPPUNIT_ASSERT(*pRTL);
+
+ aArgs.GetNextRun(nMinRunPos, nEndRunPos, pRTL);
+ CPPUNIT_ASSERT_EQUAL(21, *nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(45, *nEndRunPos);
+ CPPUNIT_ASSERT(!*pRTL);
+
+ aArgs.GetNextRun(nMinRunPos, nEndRunPos, pRTL);
+ CPPUNIT_ASSERT_EQUAL(20, *nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(21, *nEndRunPos);
+ CPPUNIT_ASSERT(*pRTL);
+
+ aArgs.GetNextRun(nMinRunPos, nEndRunPos, pRTL);
+ CPPUNIT_ASSERT_EQUAL(0, *nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(19, *nEndRunPos);
+ CPPUNIT_ASSERT(!*pRTL);
+}
+
+void VclTextTest::testImplLayoutArgsRightAlign()
+{
+ OUString sTestString = u"The quick brown fox\n jumped over the lazy dog"
+ "العاشر";
+ vcl::text::ImplLayoutArgs aArgs(sTestString, 0, sTestString.getLength(),
+ SalLayoutFlags::RightAlign, LanguageTag(LANGUAGE_NONE),
+ nullptr);
+
+ int* nMinRunPos = new int(0);
+ int* nEndRunPos = new int(0);
+ bool* pRTL = new bool(false);
+
+ aArgs.GetNextRun(nMinRunPos, nEndRunPos, pRTL);
+ CPPUNIT_ASSERT_EQUAL(0, *nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(19, *nEndRunPos);
+ CPPUNIT_ASSERT(!*pRTL);
+
+ aArgs.GetNextRun(nMinRunPos, nEndRunPos, pRTL);
+ CPPUNIT_ASSERT_EQUAL(20, *nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(45, *nEndRunPos);
+ CPPUNIT_ASSERT(!*pRTL);
+
+ aArgs.GetNextRun(nMinRunPos, nEndRunPos, pRTL);
+ CPPUNIT_ASSERT_EQUAL(45, *nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(51, *nEndRunPos);
+ CPPUNIT_ASSERT(*pRTL);
+}
+
+void VclTextTest::testImplLayoutArgs_PrepareFallback_precalculatedglyphs()
+{
+ // this font has no latin characters and thus needs fallback
+ const vcl::Font aFont("KacstBook", Size(0, 36));
+
+ ScopedVclPtrInstance<VirtualDevice> pVirDev;
+ pVirDev->SetFont(aFont);
+
+ const OUString sTestString = "The quick\n jumped over";
+ std::unique_ptr<SalLayout> pLayout
+ = pVirDev->ImplLayout(sTestString, 0, sTestString.getLength(), Point(0, 0), 0, nullptr,
+ SalLayoutFlags::GlyphItemsOnly);
+ SalLayoutGlyphs aGlyphs = pLayout->GetGlyphs();
+ SalLayoutGlyphsImpl* pGlyphsImpl = aGlyphs.Impl(1);
+
+ vcl::text::ImplLayoutArgs aArgs(sTestString, 0, sTestString.getLength(),
+ SalLayoutFlags::BiDiRtl, LanguageTag(LANGUAGE_LATIN), nullptr);
+
+ aArgs.PrepareFallback(pGlyphsImpl);
+
+ int* nMinRunPos = new int(0);
+ int* nEndRunPos = new int(0);
+ bool* pRTL = new bool(false);
+
+ aArgs.GetNextRun(nMinRunPos, nEndRunPos, pRTL);
+ CPPUNIT_ASSERT_EQUAL(0, *nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(3, *nEndRunPos);
+ CPPUNIT_ASSERT(!*pRTL);
+
+ aArgs.GetNextRun(nMinRunPos, nEndRunPos, pRTL);
+ CPPUNIT_ASSERT_EQUAL(4, *nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(9, *nEndRunPos);
+ CPPUNIT_ASSERT(!*pRTL);
+
+ aArgs.GetNextRun(nMinRunPos, nEndRunPos, pRTL);
+ CPPUNIT_ASSERT_EQUAL(11, *nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(17, *nEndRunPos);
+ CPPUNIT_ASSERT(!*pRTL);
+
+ aArgs.GetNextRun(nMinRunPos, nEndRunPos, pRTL);
+ CPPUNIT_ASSERT_EQUAL(18, *nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(22, *nEndRunPos);
+ CPPUNIT_ASSERT(!*pRTL);
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(VclTextTest);
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/vcl/source/gdi/CommonSalLayout.cxx b/vcl/source/gdi/CommonSalLayout.cxx
index b6a489a88a9a..fbfacdee6b02 100644
--- a/vcl/source/gdi/CommonSalLayout.cxx
+++ b/vcl/source/gdi/CommonSalLayout.cxx
@@ -25,6 +25,7 @@
#include <vcl/font/Feature.hxx>
#include <vcl/font/FeatureParser.hxx>
+#include <ImplLayoutArgs.hxx>
#include <TextLayoutCache.hxx>
#include <fontselect.hxx>
#include <salgdi.hxx>
@@ -162,7 +163,7 @@ SalLayoutGlyphs GenericSalLayout::GetGlyphs() const
return glyphs;
}
-void GenericSalLayout::SetNeedFallback(ImplLayoutArgs& rArgs, sal_Int32 nCharPos, bool bRightToLeft)
+void GenericSalLayout::SetNeedFallback(vcl::text::ImplLayoutArgs& rArgs, sal_Int32 nCharPos, bool bRightToLeft)
{
if (nCharPos < 0 || mbFuzzing)
return;
@@ -190,7 +191,7 @@ void GenericSalLayout::SetNeedFallback(ImplLayoutArgs& rArgs, sal_Int32 nCharPos
rArgs.AddFallbackRun(nGraphemeStartPos, nGraphemeEndPos, bRightToLeft);
}
-void GenericSalLayout::AdjustLayout(ImplLayoutArgs& rArgs)
+void GenericSalLayout::AdjustLayout(vcl::text::ImplLayoutArgs& rArgs)
{
SalLayout::AdjustLayout(rArgs);
@@ -251,7 +252,7 @@ bool GenericSalLayout::HasVerticalAlternate(sal_UCS4 aChar, sal_UCS4 aVariationS
return hb_set_has(mpVertGlyphs, nGlyphIndex) != 0;
}
-bool GenericSalLayout::LayoutText(ImplLayoutArgs& rArgs, const SalLayoutGlyphsImpl* pGlyphs)
+bool GenericSalLayout::LayoutText(vcl::text::ImplLayoutArgs& rArgs, const SalLayoutGlyphsImpl* pGlyphs)
{
// No need to touch m_GlyphItems at all for an empty string.
if (rArgs.mnEndCharPos - rArgs.mnMinCharPos <= 0)
diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx
index e731d6782cca..debe3017a92a 100644
--- a/vcl/source/gdi/sallayout.cxx
+++ b/vcl/source/gdi/sallayout.cxx
@@ -27,6 +27,7 @@
#include <math.h>
+#include <ImplLayoutArgs.hxx>
#include <salgdi.hxx>
#include <sallayout.hxx>
#include <basegfx/polygon/b2dpolypolygon.hxx>
@@ -49,85 +50,6 @@
#define GF_FONTSHIFT 28
-std::ostream &operator <<(std::ostream& s, ImplLayoutArgs const &rArgs)
-{
-#ifndef SAL_LOG_INFO
- (void) rArgs;
-#else
- s << "ImplLayoutArgs{";
-
- s << "Flags=";
- if (rArgs.mnFlags == SalLayoutFlags::NONE)
- s << 0;
- else {
- bool need_or = false;
- s << "{";
-#define TEST(x) if (rArgs.mnFlags & SalLayoutFlags::x) { if (need_or) s << "|"; s << #x; need_or = true; }
- TEST(BiDiRtl);
- TEST(BiDiStrong);
- TEST(RightAlign);
- TEST(DisableKerning);
- TEST(KerningAsian);
- TEST(Vertical);
- TEST(KashidaJustification);
- TEST(ForFallback);
-#undef TEST
- s << "}";
- }
-
- const int nLength = rArgs.mrStr.getLength();
-
- s << ",Length=" << nLength;
- s << ",MinCharPos=" << rArgs.mnMinCharPos;
- s << ",EndCharPos=" << rArgs.mnEndCharPos;
-
- s << ",Str=\"";
- int lim = nLength;
- if (lim > 10)
- lim = 7;
- for (int i = 0; i < lim; i++) {
- if (rArgs.mrStr[i] == '\n')
- s << "\\n";
- else if (rArgs.mrStr[i] < ' ' || (rArgs.mrStr[i] >= 0x7F && rArgs.mrStr[i] <= 0xFF))
- s << "\\0x" << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(rArgs.mrStr[i]) << std::setfill(' ') << std::setw(1) << std::dec;
- else if (rArgs.mrStr[i] < 0x7F)
- s << static_cast<char>(rArgs.mrStr[i]);
- else
- s << "\\u" << std::hex << std::setw(4) << std::setfill('0') << static_cast<int>(rArgs.mrStr[i]) << std::setfill(' ') << std::setw(1) << std::dec;
- }
- if (nLength > lim)
- s << "...";
- s << "\"";
-
- s << ",DXArray=";
- if (rArgs.mpDXArray) {
- s << "[";
- int count = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
- lim = count;
- if (lim > 10)
- lim = 7;
- for (int i = 0; i < lim; i++) {
- s << rArgs.mpDXArray[i];
- if (i < lim-1)
- s << ",";
- }
- if (count > lim) {
- if (count > lim + 1)
- s << "...";
- s << rArgs.mpDXArray[count-1];
- }
- s << "]";
- } else
- s << "NULL";
-
- s << ",LayoutWidth=" << rArgs.mnLayoutWidth;
-
- s << "}";
-
-#endif
- return s;
-}
-
sal_UCS4 GetMirroredChar( sal_UCS4 nChar )
{
nChar = u_charMirror( nChar );
@@ -207,27 +129,6 @@ sal_UCS4 GetLocalizedChar( sal_UCS4 nChar, LanguageType eLang )
return nChar;
}
-static bool IsControlChar( sal_UCS4 cChar )
-{
- // C0 control characters
- if( (0x0001 <= cChar) && (cChar <= 0x001F) )
- return true;
- // formatting characters
- if( (0x200E <= cChar) && (cChar <= 0x200F) )
- return true;
- if( (0x2028 <= cChar) && (cChar <= 0x202E) )
- return true;
- // deprecated formatting characters
- if( (0x206A <= cChar) && (cChar <= 0x206F) )
- return true;
- if( 0x2060 == cChar )
- return true;
- // byte order markers and invalid unicode
- if( (cChar == 0xFEFF) || (cChar == 0xFFFE) || (cChar == 0xFFFF) )
- return true;
- return false;
-}
-
void ImplLayoutRuns::AddPos( int nCharPos, bool bRTL )
{
// check if charpos could extend current run
@@ -385,175 +286,6 @@ bool ImplLayoutRuns::GetRun( int* nMinRunPos, int* nEndRunPos, bool* bRightToLef
return true;
}
-ImplLayoutArgs::ImplLayoutArgs(const OUString& rStr,
- int nMinCharPos, int nEndCharPos, SalLayoutFlags nFlags, const LanguageTag& rLanguageTag,
- vcl::text::TextLayoutCache const*const pLayoutCache)
-:
- maLanguageTag( rLanguageTag ),
- mnFlags( nFlags ),
- mrStr( rStr ),
- mnMinCharPos( nMinCharPos ),
- mnEndCharPos( nEndCharPos ),
- m_pTextLayoutCache(pLayoutCache),
- mpDXArray( nullptr ),
- mnLayoutWidth( 0 ),
- mnOrientation( 0 )
-{
- if( mnFlags & SalLayoutFlags::BiDiStrong )
- {
- // handle strong BiDi mode
-
- // do not bother to BiDi analyze strong LTR/RTL
- // TODO: can we assume these strings do not have unicode control chars?
- // if not remove the control characters from the runs
- bool bRTL(mnFlags & SalLayoutFlags::BiDiRtl);
- AddRun( mnMinCharPos, mnEndCharPos, bRTL );
- }
- else
- {
- // handle weak BiDi mode
- UBiDiLevel nLevel = (mnFlags & SalLayoutFlags::BiDiRtl)? 1 : 0;
-
- // prepare substring for BiDi analysis
- // TODO: reuse allocated pParaBidi
- UErrorCode rcI18n = U_ZERO_ERROR;
- const int nLength = mrStr.getLength();
- UBiDi* pParaBidi = ubidi_openSized(nLength, 0, &rcI18n);
- if( !pParaBidi )
- return;
- ubidi_setPara(pParaBidi, reinterpret_cast<const UChar *>(mrStr.getStr()), nLength, nLevel, nullptr, &rcI18n);
-
- UBiDi* pLineBidi = pParaBidi;
- int nSubLength = mnEndCharPos - mnMinCharPos;
- if (nSubLength != nLength)
- {
- pLineBidi = ubidi_openSized( nSubLength, 0, &rcI18n );
- ubidi_setLine( pParaBidi, mnMinCharPos, mnEndCharPos, pLineBidi, &rcI18n );
- }
-
- // run BiDi algorithm
- const int nRunCount = ubidi_countRuns( pLineBidi, &rcI18n );
- //maRuns.resize( 2 * nRunCount );
- for( int i = 0; i < nRunCount; ++i )
- {
- int32_t nMinPos, nRunLength;
- const UBiDiDirection nDir = ubidi_getVisualRun( pLineBidi, i, &nMinPos, &nRunLength );
- const int nPos0 = nMinPos + mnMinCharPos;
- const int nPos1 = nPos0 + nRunLength;
-
- const bool bRTL = (nDir == UBIDI_RTL);
- AddRun( nPos0, nPos1, bRTL );
- }
-
- // cleanup BiDi engine
- if( pLineBidi != pParaBidi )
- ubidi_close( pLineBidi );
- ubidi_close( pParaBidi );
- }
-
- // prepare calls to GetNextPos/GetNextRun
- maRuns.ResetPos();
-}
-
-// add a run after splitting it up to get rid of control chars
-void ImplLayoutArgs::AddRun( int nCharPos0, int nCharPos1, bool bRTL )
-{
- SAL_WARN_IF( nCharPos0 > nCharPos1, "vcl", "ImplLayoutArgs::AddRun() nCharPos0>=nCharPos1" );
-
- // remove control characters from runs by splitting them up
- if( !bRTL )
- {
- for( int i = nCharPos0; i < nCharPos1; ++i )
- if( IsControlChar( mrStr[i] ) )
- {
- // add run until control char
- maRuns.AddRun( nCharPos0, i, bRTL );
- nCharPos0 = i + 1;
- }
- }
- else
- {
- for( int i = nCharPos1; --i >= nCharPos0; )
- if( IsControlChar( mrStr[i] ) )
- {
- // add run until control char
- maRuns.AddRun( i+1, nCharPos1, bRTL );
- nCharPos1 = i;
- }
- }
-
- // add remainder of run
- maRuns.AddRun( nCharPos0, nCharPos1, bRTL );
-}
-
-bool ImplLayoutArgs::PrepareFallback(const SalLayoutGlyphsImpl* pGlyphsImpl)
-{
- // Generate runs with pre-calculated glyph items instead maFallbackRuns.
- if( pGlyphsImpl != nullptr )
- {
- maRuns.Clear();
- maFallbackRuns.Clear();
-
- for (auto const& aGlyphItem : *pGlyphsImpl)
- {
- for(int i = aGlyphItem.charPos(); i < aGlyphItem.charPos() + aGlyphItem.charCount(); ++i)
- maRuns.AddPos(i, aGlyphItem.IsRTLGlyph());
- }
-
- return !maRuns.IsEmpty();
- }
-
- // short circuit if no fallback is needed
- if( maFallbackRuns.IsEmpty() )
- {
- maRuns.Clear();
- return false;
- }
-
- // convert the fallback requests to layout requests
- bool bRTL;
- int nMin, nEnd;
-
- // get the individual fallback requests
- std::vector<int> aPosVector;
- aPosVector.reserve(mrStr.getLength());
- maFallbackRuns.ResetPos();
- for(; maFallbackRuns.GetRun( &nMin, &nEnd, &bRTL ); maFallbackRuns.NextRun() )
- for( int i = nMin; i < nEnd; ++i )
- aPosVector.push_back( i );
- maFallbackRuns.Clear();
-
- // sort the individual fallback requests
- std::sort( aPosVector.begin(), aPosVector.end() );
-
- // adjust fallback runs to have the same order and limits of the original runs
- ImplLayoutRuns aNewRuns;
- maRuns.ResetPos();
- for(; maRuns.GetRun( &nMin, &nEnd, &bRTL ); maRuns.NextRun() )
- {
- if( !bRTL) {
- auto it = std::lower_bound( aPosVector.begin(), aPosVector.end(), nMin );
- for(; (it != aPosVector.end()) && (*it < nEnd); ++it )
- aNewRuns.AddPos( *it, bRTL );
- } else {
- auto it = std::upper_bound( aPosVector.begin(), aPosVector.end(), nEnd );
- while( (it != aPosVector.begin()) && (*--it >= nMin) )
- aNewRuns.AddPos( *it, bRTL );
- }
- }
-
- maRuns = aNewRuns; // TODO: use vector<>::swap()
- maRuns.ResetPos();
- return true;
-}
-
-bool ImplLayoutArgs::GetNextRun( int* nMinRunPos, int* nEndRunPos, bool* bRTL )
-{
- bool bValid = maRuns.GetRun( nMinRunPos, nEndRunPos, bRTL );
- maRuns.NextRun();
- return bValid;
-}
-
SalLayout::SalLayout()
: mnMinCharPos( -1 ),
mnEndCharPos( -1 ),
@@ -565,7 +297,7 @@ SalLayout::SalLayout()
SalLayout::~SalLayout()
{}
-void SalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
+void SalLayout::AdjustLayout( vcl::text::ImplLayoutArgs& rArgs )
{
mnMinCharPos = rArgs.mnMinCharPos;
mnEndCharPos = rArgs.mnEndCharPos;
@@ -1047,7 +779,7 @@ void MultiSalLayout::AddFallback( std::unique_ptr<SalLayout> pFallback,
++mnLevel;
}
-bool MultiSalLayout::LayoutText( ImplLayoutArgs& rArgs, const SalLayoutGlyphsImpl* )
+bool MultiSalLayout::LayoutText( vcl::text::ImplLayoutArgs& rArgs, const SalLayoutGlyphsImpl* )
{
if( mnLevel <= 1 )
return false;
@@ -1056,10 +788,10 @@ bool MultiSalLayout::LayoutText( ImplLayoutArgs& rArgs, const SalLayoutGlyphsImp
return true;
}
-void MultiSalLayout::AdjustLayout( ImplLayoutArgs& rArgs )
+void MultiSalLayout::AdjustLayout( vcl::text::ImplLayoutArgs& rArgs )
{
SalLayout::AdjustLayout( rArgs );
- ImplLayoutArgs aMultiArgs = rArgs;
+ vcl::text::ImplLayoutArgs aMultiArgs = rArgs;
std::vector<DeviceCoordinate> aJustificationArray;
if( !rArgs.mpDXArray && rArgs.mnLayoutWidth )
diff --git a/vcl/source/outdev/font.cxx b/vcl/source/outdev/font.cxx
index 1875394eaf93..06c339dd795c 100644
--- a/vcl/source/outdev/font.cxx
+++ b/vcl/source/outdev/font.cxx
@@ -35,6 +35,7 @@
#include <outdev.h>
#include <window.h>
+#include <ImplLayoutArgs.hxx>
#include <PhysicalFontCollection.hxx>
#include <drawmode.hxx>
#include <font/FeatureCollector.hxx>
@@ -1253,7 +1254,7 @@ void OutputDevice::ImplDrawEmphasisMarks( SalLayout& rSalLayout )
std::unique_ptr<SalLayout> OutputDevice::getFallbackLayout(
LogicalFontInstance* pLogicalFont, int nFallbackLevel,
- ImplLayoutArgs& rLayoutArgs, const SalLayoutGlyphs* pGlyphs) const
+ vcl::text::ImplLayoutArgs& rLayoutArgs, const SalLayoutGlyphs* pGlyphs) const
{
// we need a graphics
if (!mpGraphics && !AcquireGraphics())
@@ -1278,7 +1279,7 @@ std::unique_ptr<SalLayout> OutputDevice::getFallbackLayout(
}
std::unique_ptr<SalLayout> OutputDevice::ImplGlyphFallbackLayout( std::unique_ptr<SalLayout> pSalLayout,
- ImplLayoutArgs& rLayoutArgs, const SalLayoutGlyphs* pGlyphs ) const
+ vcl::text::ImplLayoutArgs& rLayoutArgs, const SalLayoutGlyphs* pGlyphs ) const
{
// This function relies on a valid mpFontInstance, if it doesn't exist bail out
// - we'd have crashed later on anyway. At least here we can catch the error in debug
diff --git a/vcl/source/outdev/text.cxx b/vcl/source/outdev/text.cxx
index 7d5fe5256353..801615401fcd 100644
--- a/vcl/source/outdev/text.cxx
+++ b/vcl/source/outdev/text.cxx
@@ -41,6 +41,7 @@
#include <config_fuzzers.h>
#include <outdev.h>
+#include <ImplLayoutArgs.hxx>
#include <drawmode.hxx>
#include <salgdi.hxx>
#include <svdata.hxx>
@@ -1095,7 +1096,7 @@ void OutputDevice::DrawStretchText( const Point& rStartPt, sal_uLong nWidth,
mpAlphaVDev->DrawStretchText( rStartPt, nWidth, rStr, nIndex, nLen );
}
-ImplLayoutArgs OutputDevice::ImplPrepareLayoutArgs( OUString& rStr,
+vcl::text::ImplLayoutArgs OutputDevice::ImplPrepareLayoutArgs( OUString& rStr,
const sal_Int32 nMinIndex, const sal_Int32 nLen,
DeviceCoordinate nPixelWidth, const DeviceCoordinate* pDXArray,
SalLayoutFlags nLayoutFlags,
@@ -1184,7 +1185,7 @@ ImplLayoutArgs OutputDevice::ImplPrepareLayoutArgs( OUString& rStr,
nLayoutFlags |= SalLayoutFlags::RightAlign;
// set layout options
- ImplLayoutArgs aLayoutArgs(rStr, nMinIndex, nEndIndex, nLayoutFlags, maFont.GetLanguageTag(), pLayoutCache);
+ vcl::text::ImplLayoutArgs aLayoutArgs(rStr, nMinIndex, nEndIndex, nLayoutFlags, maFont.GetLanguageTag(), pLayoutCache);
Degree10 nOrientation = mpFontInstance ? mpFontInstance->mnOrientation : 0_deg10;
aLayoutArgs.SetOrientation( nOrientation );
@@ -1267,7 +1268,7 @@ std::unique_ptr<SalLayout> OutputDevice::ImplLayout(const OUString& rOrigStr,
}
}
- ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nMinIndex, nLen,
+ vcl::text::ImplLayoutArgs aLayoutArgs = ImplPrepareLayoutArgs( aStr, nMinIndex, nLen,
nPixelWidth, pDXPixelArray, flags, pLayoutCache);
// get matching layout object for base font
@@ -1320,7 +1321,7 @@ std::shared_ptr<vcl::text::TextLayoutCache> OutputDevice::CreateTextLayoutCache(
bool OutputDevice::GetTextIsRTL( const OUString& rString, sal_Int32 nIndex, sal_Int32 nLen ) const
{
OUString aStr( rString );
- ImplLayoutArgs aArgs = ImplPrepareLayoutArgs( aStr, nIndex, nLen, 0, nullptr );
+ vcl::text::ImplLayoutArgs aArgs = ImplPrepareLayoutArgs( aStr, nIndex, nLen, 0, nullptr );
bool bRTL = false;
int nCharPos = -1;
if (!aArgs.GetNextPos(&nCharPos, &bRTL))
diff --git a/vcl/source/text/ImplLayoutArgs.cxx b/vcl/source/text/ImplLayoutArgs.cxx
new file mode 100644
index 000000000000..7957d1ace824
--- /dev/null
+++ b/vcl/source/text/ImplLayoutArgs.cxx
@@ -0,0 +1,339 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <ImplLayoutArgs.hxx>
+
+#include <unicode/ubidi.h>
+#include <unicode/uchar.h>
+
+#include <algorithm>
+#include <memory>
+
+namespace vcl::text
+{
+ImplLayoutArgs::ImplLayoutArgs(const OUString& rStr, int nMinCharPos, int nEndCharPos,
+ SalLayoutFlags nFlags, const LanguageTag& rLanguageTag,
+ vcl::text::TextLayoutCache const* const pLayoutCache)
+ : maLanguageTag(rLanguageTag)
+ , mnFlags(nFlags)
+ , mrStr(rStr)
+ , mnMinCharPos(nMinCharPos)
+ , mnEndCharPos(nEndCharPos)
+ , m_pTextLayoutCache(pLayoutCache)
+ , mpDXArray(nullptr)
+ , mnLayoutWidth(0)
+ , mnOrientation(0)
+{
+ if (mnFlags & SalLayoutFlags::BiDiStrong)
+ {
+ // handle strong BiDi mode
+
+ // do not bother to BiDi analyze strong LTR/RTL
+ // TODO: can we assume these strings do not have unicode control chars?
+ // if not remove the control characters from the runs
+ bool bRTL(mnFlags & SalLayoutFlags::BiDiRtl);
+ AddRun(mnMinCharPos, mnEndCharPos, bRTL);
+ }
+ else
+ {
+ // handle weak BiDi mode
+ UBiDiLevel nLevel = (mnFlags & SalLayoutFlags::BiDiRtl) ? 1 : 0;
+
+ // prepare substring for BiDi analysis
+ // TODO: reuse allocated pParaBidi
+ UErrorCode rcI18n = U_ZERO_ERROR;
+ const int nLength = mrStr.getLength();
+ UBiDi* pParaBidi = ubidi_openSized(nLength, 0, &rcI18n);
+ if (!pParaBidi)
+ return;
+ ubidi_setPara(pParaBidi, reinterpret_cast<const UChar*>(mrStr.getStr()), nLength, nLevel,
+ nullptr, &rcI18n);
+
+ UBiDi* pLineBidi = pParaBidi;
+ int nSubLength = mnEndCharPos - mnMinCharPos;
+ if (nSubLength != nLength)
+ {
+ pLineBidi = ubidi_openSized(nSubLength, 0, &rcI18n);
+ ubidi_setLine(pParaBidi, mnMinCharPos, mnEndCharPos, pLineBidi, &rcI18n);
+ }
+
+ // run BiDi algorithm
+ const int nRunCount = ubidi_countRuns(pLineBidi, &rcI18n);
+ //maRuns.resize( 2 * nRunCount );
+ for (int i = 0; i < nRunCount; ++i)
+ {
+ int32_t nMinPos, nRunLength;
+ const UBiDiDirection nDir = ubidi_getVisualRun(pLineBidi, i, &nMinPos, &nRunLength);
+ const int nPos0 = nMinPos + mnMinCharPos;
+ const int nPos1 = nPos0 + nRunLength;
+
+ const bool bRTL = (nDir == UBIDI_RTL);
+ AddRun(nPos0, nPos1, bRTL);
+ }
+
+ // cleanup BiDi engine
+ if (pLineBidi != pParaBidi)
+ ubidi_close(pLineBidi);
+ ubidi_close(pParaBidi);
+ }
+
+ // prepare calls to GetNextPos/GetNextRun
+ maRuns.ResetPos();
+}
+
+void ImplLayoutArgs::SetLayoutWidth(DeviceCoordinate nWidth) { mnLayoutWidth = nWidth; }
+
+void ImplLayoutArgs::SetDXArray(DeviceCoordinate const* pDXArray) { mpDXArray = pDXArray; }
+
+void ImplLayoutArgs::SetOrientation(Degree10 nOrientation) { mnOrientation = nOrientation; }
+
+void ImplLayoutArgs::ResetPos() { maRuns.ResetPos(); }
+
+bool ImplLayoutArgs::GetNextPos(int* nCharPos, bool* bRTL)
+{
+ return maRuns.GetNextPos(nCharPos, bRTL);
+}
+
+void ImplLayoutArgs::AddFallbackRun(int nMinRunPos, int nEndRunPos, bool bRTL)
+{
+ maFallbackRuns.AddRun(nMinRunPos, nEndRunPos, bRTL);
+}
+
+bool ImplLayoutArgs::HasFallbackRun() const { return !maFallbackRuns.IsEmpty(); }
+
+static bool IsControlChar(sal_UCS4 cChar)
+{
+ // C0 control characters
+ if ((0x0001 <= cChar) && (cChar <= 0x001F))
+ return true;
+ // formatting characters
+ if ((0x200E <= cChar) && (cChar <= 0x200F))
+ return true;
+ if ((0x2028 <= cChar) && (cChar <= 0x202E))
+ return true;
+ // deprecated formatting characters
+ if ((0x206A <= cChar) && (cChar <= 0x206F))
+ return true;
+ if (0x2060 == cChar)
+ return true;
+ // byte order markers and invalid unicode
+ if ((cChar == 0xFEFF) || (cChar == 0xFFFE) || (cChar == 0xFFFF))
+ return true;
+ return false;
+}
+
+// add a run after splitting it up to get rid of control chars
+void ImplLayoutArgs::AddRun(int nCharPos0, int nCharPos1, bool bRTL)
+{
+ SAL_WARN_IF(nCharPos0 > nCharPos1, "vcl", "ImplLayoutArgs::AddRun() nCharPos0>=nCharPos1");
+
+ // remove control characters from runs by splitting them up
+ if (!bRTL)
+ {
+ for (int i = nCharPos0; i < nCharPos1; ++i)
+ if (IsControlChar(mrStr[i]))
+ {
+ // add run until control char
+ maRuns.AddRun(nCharPos0, i, bRTL);
+ nCharPos0 = i + 1;
+ }
+ }
+ else
+ {
+ for (int i = nCharPos1; --i >= nCharPos0;)
+ if (IsControlChar(mrStr[i]))
+ {
+ // add run until control char
+ maRuns.AddRun(i + 1, nCharPos1, bRTL);
+ nCharPos1 = i;
+ }
+ }
+
+ // add remainder of run
+ maRuns.AddRun(nCharPos0, nCharPos1, bRTL);
+}
+
+bool ImplLayoutArgs::PrepareFallback(const SalLayoutGlyphsImpl* pGlyphsImpl)
+{
+ // Generate runs with pre-calculated glyph items instead maFallbackRuns.
+ if (pGlyphsImpl != nullptr)
+ {
+ maRuns.Clear();
+ maFallbackRuns.Clear();
+
+ for (auto const& aGlyphItem : *pGlyphsImpl)
+ {
+ for (int i = aGlyphItem.charPos(); i < aGlyphItem.charPos() + aGlyphItem.charCount();
+ ++i)
+ maRuns.AddPos(i, aGlyphItem.IsRTLGlyph());
+ }
+
+ return !maRuns.IsEmpty();
+ }
+
+ // short circuit if no fallback is needed
+ if (maFallbackRuns.IsEmpty())
+ {
+ maRuns.Clear();
+ return false;
+ }
+
+ // convert the fallback requests to layout requests
+ bool bRTL;
+ int nMin, nEnd;
+
+ // get the individual fallback requests
+ std::vector<int> aPosVector;
+ aPosVector.reserve(mrStr.getLength());
+ maFallbackRuns.ResetPos();
+ for (; maFallbackRuns.GetRun(&nMin, &nEnd, &bRTL); maFallbackRuns.NextRun())
+ for (int i = nMin; i < nEnd; ++i)
+ aPosVector.push_back(i);
+ maFallbackRuns.Clear();
+
+ // sort the individual fallback requests
+ std::sort(aPosVector.begin(), aPosVector.end());
+
+ // adjust fallback runs to have the same order and limits of the original runs
+ ImplLayoutRuns aNewRuns;
+ maRuns.ResetPos();
+ for (; maRuns.GetRun(&nMin, &nEnd, &bRTL); maRuns.NextRun())
+ {
+ if (!bRTL)
+ {
+ auto it = std::lower_bound(aPosVector.begin(), aPosVector.end(), nMin);
+ for (; (it != aPosVector.end()) && (*it < nEnd); ++it)
+ aNewRuns.AddPos(*it, bRTL);
+ }
+ else
+ {
+ auto it = std::upper_bound(aPosVector.begin(), aPosVector.end(), nEnd);
+ while ((it != aPosVector.begin()) && (*--it >= nMin))
+ aNewRuns.AddPos(*it, bRTL);
+ }
+ }
+
+ maRuns = aNewRuns; // TODO: use vector<>::swap()
+ maRuns.ResetPos();
+ return true;
+}
+
+bool ImplLayoutArgs::GetNextRun(int* nMinRunPos, int* nEndRunPos, bool* bRTL)
+{
+ bool bValid = maRuns.GetRun(nMinRunPos, nEndRunPos, bRTL);
+ maRuns.NextRun();
+ return bValid;
+}
+}
+
+std::ostream& operator<<(std::ostream& s, vcl::text::ImplLayoutArgs const& rArgs)
+{
+#ifndef SAL_LOG_INFO
+ (void)rArgs;
+#else
+ s << "ImplLayoutArgs{";
+
+ s << "Flags=";
+ if (rArgs.mnFlags == SalLayoutFlags::NONE)
+ s << 0;
+ else
+ {
+ bool need_or = false;
+ s << "{";
+#define TEST(x) \
+ if (rArgs.mnFlags & SalLayoutFlags::x) \
+ { \
+ if (need_or) \
+ s << "|"; \
+ s << #x; \
+ need_or = true; \
+ }
+ TEST(BiDiRtl);
+ TEST(BiDiStrong);
+ TEST(RightAlign);
+ TEST(DisableKerning);
+ TEST(KerningAsian);
+ TEST(Vertical);
+ TEST(KashidaJustification);
+ TEST(ForFallback);
+#undef TEST
+ s << "}";
+ }
+
+ const int nLength = rArgs.mrStr.getLength();
+
+ s << ",Length=" << nLength;
+ s << ",MinCharPos=" << rArgs.mnMinCharPos;
+ s << ",EndCharPos=" << rArgs.mnEndCharPos;
+
+ s << ",Str=\"";
+ int lim = nLength;
+ if (lim > 10)
+ lim = 7;
+ for (int i = 0; i < lim; i++)
+ {
+ if (rArgs.mrStr[i] == '\n')
+ s << "\\n";
+ else if (rArgs.mrStr[i] < ' ' || (rArgs.mrStr[i] >= 0x7F && rArgs.mrStr[i] <= 0xFF))
+ s << "\\0x" << std::hex << std::setw(2) << std::setfill('0')
+ << static_cast<int>(rArgs.mrStr[i]) << std::setfill(' ') << std::setw(1) << std::dec;
+ else if (rArgs.mrStr[i] < 0x7F)
+ s << static_cast<char>(rArgs.mrStr[i]);
+ else
+ s << "\\u" << std::hex << std::setw(4) << std::setfill('0')
+ << static_cast<int>(rArgs.mrStr[i]) << std::setfill(' ') << std::setw(1) << std::dec;
+ }
+ if (nLength > lim)
+ s << "...";
+ s << "\"";
+
+ s << ",DXArray=";
+ if (rArgs.mpDXArray)
+ {
+ s << "[";
+ int count = rArgs.mnEndCharPos - rArgs.mnMinCharPos;
+ lim = count;
+ if (lim > 10)
+ lim = 7;
+ for (int i = 0; i < lim; i++)
+ {
+ s << rArgs.mpDXArray[i];
+ if (i < lim - 1)
+ s << ",";
+ }
+ if (count > lim)
+ {
+ if (count > lim + 1)
+ s << "...";
+ s << rArgs.mpDXArray[count - 1];
+ }
+ s << "]";
+ }
+ else
+ s << "NULL";
+
+ s << ",LayoutWidth=" << rArgs.mnLayoutWidth;
+
+ s << "}";
+
+#endif
+ return s;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
More information about the Libreoffice-commits
mailing list