summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Sherlock <chris.sherlock79@gmail.com>2021-08-28 22:50:26 +1000
committerNoel Grandin <noel.grandin@collabora.co.uk>2021-09-06 12:52:38 +0200
commitdb0a6e1bd98a9430e9ca4edfaabc3b11da986592 (patch)
treecd7b59825ade08a1455cbea979f321278c791ada
parent8381242c2e0bfda1b37e7e82525926c0497c81d4 (diff)
vcl: migrate ImplLayoutRuns to own files
Wrote a set of unit tests for ImplLayoutRuns, and added ImplLayoutRuns to vcl::text namespace. Change-Id: Id6ae8882acb8e3d821bb38551e78019cbdcaa662 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/121204 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
-rw-r--r--solenv/clang-format/excludelist1
-rw-r--r--vcl/Library_vcl.mk1
-rw-r--r--vcl/inc/ImplLayoutRuns.hxx53
-rw-r--r--vcl/inc/sallayout.hxx45
-rw-r--r--vcl/qa/cppunit/text.cxx190
-rw-r--r--vcl/source/gdi/sallayout.cxx157
-rw-r--r--vcl/source/text/ImplLayoutRuns.cxx179
7 files changed, 435 insertions, 191 deletions
diff --git a/solenv/clang-format/excludelist b/solenv/clang-format/excludelist
index a484535c29b1..0c69494826dd 100644
--- a/solenv/clang-format/excludelist
+++ b/solenv/clang-format/excludelist
@@ -15049,6 +15049,7 @@ vcl/source/outdev/textline.cxx
vcl/source/outdev/transparent.cxx
vcl/source/outdev/vclreferencebase.cxx
vcl/source/outdev/wallpaper.cxx
+vcl/source/text/ImplLayoutRuns.cxx
vcl/source/toolkit/group.cxx
vcl/source/toolkit/morebtn.cxx
vcl/source/treelist/headbar.cxx
diff --git a/vcl/Library_vcl.mk b/vcl/Library_vcl.mk
index f9403f25b7e9..99632be5c5ef 100644
--- a/vcl/Library_vcl.mk
+++ b/vcl/Library_vcl.mk
@@ -255,6 +255,7 @@ $(eval $(call gb_Library_add_exception_objects,vcl,\
vcl/source/treelist/svimpbox \
vcl/source/treelist/svlbitm \
vcl/source/treelist/uiobject \
+ vcl/source/text/ImplLayoutRuns \
vcl/source/gdi/configsettings \
vcl/source/gdi/cvtgrf \
vcl/source/gdi/embeddedfontshelper \
diff --git a/vcl/inc/ImplLayoutRuns.hxx b/vcl/inc/ImplLayoutRuns.hxx
new file mode 100644
index 000000000000..30ac642f3779
--- /dev/null
+++ b/vcl/inc/ImplLayoutRuns.hxx
@@ -0,0 +1,53 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <vcl/dllapi.h>
+
+#include <vector>
+
+// used for managing runs e.g. for BiDi, glyph and script fallback
+class VCL_DLLPUBLIC ImplLayoutRuns
+{
+private:
+ int mnRunIndex;
+ std::vector<int> maRuns;
+
+public:
+ ImplLayoutRuns()
+ {
+ mnRunIndex = 0;
+ maRuns.reserve(8);
+ }
+
+ void Clear() { maRuns.clear(); }
+ void AddPos(int nCharPos, bool bRTL);
+ void AddRun(int nMinRunPos, int nEndRunPos, bool bRTL);
+
+ bool IsEmpty() const { return maRuns.empty(); }
+ void ResetPos() { mnRunIndex = 0; }
+ void NextRun() { mnRunIndex += 2; }
+ bool GetRun(int* nMinRunPos, int* nEndRunPos, bool* bRTL) const;
+ bool GetNextPos(int* nCharPos, bool* bRTL);
+ bool PosIsInRun(int nCharPos) const;
+ bool PosIsInAnyRun(int nCharPos) const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/inc/sallayout.hxx b/vcl/inc/sallayout.hxx
index 594202b23239..b31aa202019c 100644
--- a/vcl/inc/sallayout.hxx
+++ b/vcl/inc/sallayout.hxx
@@ -20,25 +20,27 @@
#ifndef INCLUDED_VCL_INC_SALLAYOUT_HXX
#define INCLUDED_VCL_INC_SALLAYOUT_HXX
-#include <iostream>
-#include <memory>
-#include <vector>
-
-#include <hb.h>
-
-#include <com/sun/star/i18n/XBreakIterator.hpp>
-
#include <basegfx/polygon/b2dpolypolygon.hxx>
-#include <i18nlangtag/languagetag.hxx>
#include <tools/gen.hxx>
#include <tools/degree.hxx>
+#include <i18nlangtag/languagetag.hxx>
+
#include <vcl/dllapi.h>
-#include <vcl/vclenum.hxx> // for typedef sal_UCS4
#include <vcl/devicecoordinate.hxx>
+#include <vcl/vclenum.hxx> // for typedef sal_UCS4
#include <vcl/vcllayout.hxx>
+#include "ImplLayoutRuns.hxx"
#include "impglyphitem.hxx"
+#include <com/sun/star/i18n/XBreakIterator.hpp>
+
+#include <hb.h>
+
+#include <iostream>
+#include <memory>
+#include <vector>
+
#define MAX_FALLBACK 16
@@ -50,29 +52,6 @@ namespace vcl::text {
class TextLayoutCache;
}
-// used for managing runs e.g. for BiDi, glyph and script fallback
-class ImplLayoutRuns
-{
-private:
- int mnRunIndex;
- std::vector<int> maRuns;
-
-public:
- ImplLayoutRuns() { mnRunIndex = 0; maRuns.reserve(8); }
-
- void Clear() { maRuns.clear(); }
- void AddPos( int nCharPos, bool bRTL );
- void AddRun( int nMinRunPos, int nEndRunPos, bool bRTL );
-
- bool IsEmpty() const { return maRuns.empty(); }
- void ResetPos() { mnRunIndex = 0; }
- void NextRun() { mnRunIndex += 2; }
- bool GetRun( int* nMinRunPos, int* nEndRunPos, bool* bRTL ) const;
- bool GetNextPos( int* nCharPos, bool* bRTL );
- bool PosIsInRun( int nCharPos ) const;
- bool PosIsInAnyRun( int nCharPos ) const;
-};
-
class MultiSalLayout final : public SalLayout
{
public:
diff --git a/vcl/qa/cppunit/text.cxx b/vcl/qa/cppunit/text.cxx
index c9f0d36c50c3..e56d1f27823e 100644
--- a/vcl/qa/cppunit/text.cxx
+++ b/vcl/qa/cppunit/text.cxx
@@ -10,7 +10,6 @@
#include <test/bootstrapfixture.hxx>
#include <sal/log.hxx>
#include <tools/stream.hxx>
-#include <i18nlangtag/languagetag.hxx>
#include <vcl/BitmapReadAccess.hxx>
#include <vcl/graphicfilter.hxx>
@@ -47,6 +46,10 @@ public:
void testSimpleText();
void testVerticalText();
void testTextLayoutCache();
+ void testImplLayoutRuns_AddPos();
+ void testImplLayoutRuns_AddRuns();
+ void testImplLayoutRuns_PosIsInRun();
+ void testImplLayoutRuns_PosIsInAnyRun();
void testImplLayoutArgsBiDiStrong();
void testImplLayoutArgsBiDiRtl();
void testImplLayoutArgsRightAlign();
@@ -56,6 +59,10 @@ public:
CPPUNIT_TEST(testSimpleText);
CPPUNIT_TEST(testVerticalText);
CPPUNIT_TEST(testTextLayoutCache);
+ CPPUNIT_TEST(testImplLayoutRuns_AddPos);
+ CPPUNIT_TEST(testImplLayoutRuns_AddRuns);
+ CPPUNIT_TEST(testImplLayoutRuns_PosIsInRun);
+ CPPUNIT_TEST(testImplLayoutRuns_PosIsInAnyRun);
CPPUNIT_TEST(testImplLayoutArgsBiDiStrong);
CPPUNIT_TEST(testImplLayoutArgsBiDiRtl);
CPPUNIT_TEST(testImplLayoutArgsRightAlign);
@@ -407,6 +414,187 @@ void VclTextTest::testTextLayoutCache()
CPPUNIT_ASSERT_EQUAL(51, run2.nEnd);
}
+void VclTextTest::testImplLayoutRuns_AddPos()
+{
+ ImplLayoutRuns aRuns;
+ aRuns.AddPos(1, false);
+ aRuns.AddPos(2, false);
+ aRuns.AddPos(3, false);
+ aRuns.AddPos(4, true); // add RTL marker glyph
+ aRuns.AddPos(5, false);
+ aRuns.AddPos(6, true); // add RTL marker glyph
+ aRuns.AddPos(7, false);
+
+ int* pCharPos = new int(0);
+ bool* pRightToLeftMarker = new bool(false);
+
+ CPPUNIT_ASSERT(aRuns.GetNextPos(pCharPos, pRightToLeftMarker));
+ CPPUNIT_ASSERT_EQUAL(1, *pCharPos);
+ CPPUNIT_ASSERT(!*pRightToLeftMarker);
+
+ CPPUNIT_ASSERT(aRuns.GetNextPos(pCharPos, pRightToLeftMarker));
+ CPPUNIT_ASSERT_EQUAL(2, *pCharPos);
+ CPPUNIT_ASSERT(!*pRightToLeftMarker);
+
+ CPPUNIT_ASSERT(aRuns.GetNextPos(pCharPos, pRightToLeftMarker));
+ CPPUNIT_ASSERT_EQUAL(3, *pCharPos);
+ CPPUNIT_ASSERT(!*pRightToLeftMarker);
+
+ CPPUNIT_ASSERT(aRuns.GetNextPos(pCharPos, pRightToLeftMarker));
+ CPPUNIT_ASSERT_EQUAL(4, *pCharPos);
+ CPPUNIT_ASSERT(*pRightToLeftMarker);
+
+ CPPUNIT_ASSERT(aRuns.GetNextPos(pCharPos, pRightToLeftMarker));
+ CPPUNIT_ASSERT_EQUAL(5, *pCharPos);
+ CPPUNIT_ASSERT(!*pRightToLeftMarker);
+
+ CPPUNIT_ASSERT(aRuns.GetNextPos(pCharPos, pRightToLeftMarker));
+ CPPUNIT_ASSERT_EQUAL(6, *pCharPos);
+ CPPUNIT_ASSERT(*pRightToLeftMarker);
+
+ CPPUNIT_ASSERT(aRuns.GetNextPos(pCharPos, pRightToLeftMarker));
+ CPPUNIT_ASSERT_EQUAL(7, *pCharPos);
+ CPPUNIT_ASSERT(!*pRightToLeftMarker);
+
+ // no next position, we are running off the end
+ CPPUNIT_ASSERT(!aRuns.GetNextPos(pCharPos, pRightToLeftMarker));
+
+ aRuns.ResetPos();
+
+ int nMinRunPos, nEndRunPos;
+ bool* pRightToLeft = new bool(false);
+
+ CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, pRightToLeft));
+ CPPUNIT_ASSERT_EQUAL(1, nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(4, nEndRunPos);
+ CPPUNIT_ASSERT(!*pRightToLeft);
+
+ aRuns.NextRun();
+ CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, pRightToLeft));
+ CPPUNIT_ASSERT_EQUAL(4, nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(5, nEndRunPos);
+ CPPUNIT_ASSERT(*pRightToLeft);
+
+ aRuns.NextRun();
+ CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, pRightToLeft));
+ CPPUNIT_ASSERT_EQUAL(5, nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(6, nEndRunPos);
+ CPPUNIT_ASSERT(!*pRightToLeft);
+
+ aRuns.NextRun();
+ CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, pRightToLeft));
+ CPPUNIT_ASSERT_EQUAL(6, nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(7, nEndRunPos);
+ CPPUNIT_ASSERT(*pRightToLeft);
+
+ // test clear
+ aRuns.Clear();
+ CPPUNIT_ASSERT(aRuns.IsEmpty());
+}
+
+void VclTextTest::testImplLayoutRuns_AddRuns()
+{
+ ImplLayoutRuns aRuns;
+ aRuns.AddRun(1, 4, false);
+ aRuns.AddRun(5, 4, true);
+ aRuns.AddRun(5, 6, false);
+ aRuns.AddRun(6, 7, true);
+
+ int* pCharPos = new int(0);
+ bool* pRightToLeftMarker = new bool(false);
+
+ CPPUNIT_ASSERT(aRuns.GetNextPos(pCharPos, pRightToLeftMarker));
+ CPPUNIT_ASSERT_EQUAL(1, *pCharPos);
+ CPPUNIT_ASSERT(!*pRightToLeftMarker);
+
+ CPPUNIT_ASSERT(aRuns.GetNextPos(pCharPos, pRightToLeftMarker));
+ CPPUNIT_ASSERT_EQUAL(2, *pCharPos);
+ CPPUNIT_ASSERT(!*pRightToLeftMarker);
+
+ CPPUNIT_ASSERT(aRuns.GetNextPos(pCharPos, pRightToLeftMarker));
+ CPPUNIT_ASSERT_EQUAL(3, *pCharPos);
+ CPPUNIT_ASSERT(!*pRightToLeftMarker);
+
+ CPPUNIT_ASSERT(aRuns.GetNextPos(pCharPos, pRightToLeftMarker));
+ CPPUNIT_ASSERT_EQUAL(4, *pCharPos);
+ CPPUNIT_ASSERT(*pRightToLeftMarker);
+
+ CPPUNIT_ASSERT(aRuns.GetNextPos(pCharPos, pRightToLeftMarker));
+ CPPUNIT_ASSERT_EQUAL(5, *pCharPos);
+ CPPUNIT_ASSERT(!*pRightToLeftMarker);
+
+ CPPUNIT_ASSERT(aRuns.GetNextPos(pCharPos, pRightToLeftMarker));
+ CPPUNIT_ASSERT_EQUAL(6, *pCharPos);
+ CPPUNIT_ASSERT(*pRightToLeftMarker);
+
+ // no next position, we are running off the end
+ CPPUNIT_ASSERT(!aRuns.GetNextPos(pCharPos, pRightToLeftMarker));
+
+ aRuns.ResetPos();
+
+ int nMinRunPos, nEndRunPos;
+ bool* pRightToLeft = new bool(false);
+
+ CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, pRightToLeft));
+ CPPUNIT_ASSERT_EQUAL(1, nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(4, nEndRunPos);
+ CPPUNIT_ASSERT(!*pRightToLeft);
+
+ aRuns.NextRun();
+ CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, pRightToLeft));
+ CPPUNIT_ASSERT_EQUAL(4, nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(5, nEndRunPos);
+ CPPUNIT_ASSERT(*pRightToLeft);
+
+ aRuns.NextRun();
+ CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, pRightToLeft));
+ CPPUNIT_ASSERT_EQUAL(5, nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(6, nEndRunPos);
+ CPPUNIT_ASSERT(!*pRightToLeft);
+
+ aRuns.NextRun();
+ CPPUNIT_ASSERT(aRuns.GetRun(&nMinRunPos, &nEndRunPos, pRightToLeft));
+ CPPUNIT_ASSERT_EQUAL(6, nMinRunPos);
+ CPPUNIT_ASSERT_EQUAL(7, nEndRunPos);
+ CPPUNIT_ASSERT(*pRightToLeft);
+}
+
+void VclTextTest::testImplLayoutRuns_PosIsInRun()
+{
+ ImplLayoutRuns aRuns;
+ aRuns.AddRun(1, 4, false);
+ aRuns.AddRun(4, 5, true);
+ aRuns.AddRun(5, 6, false);
+ aRuns.AddRun(6, 7, true);
+
+ CPPUNIT_ASSERT(aRuns.PosIsInRun(1));
+ CPPUNIT_ASSERT(aRuns.PosIsInRun(2));
+ CPPUNIT_ASSERT(aRuns.PosIsInRun(3));
+
+ aRuns.NextRun();
+ CPPUNIT_ASSERT(aRuns.PosIsInRun(4));
+
+ aRuns.NextRun();
+ CPPUNIT_ASSERT(aRuns.PosIsInRun(5));
+
+ aRuns.NextRun();
+ CPPUNIT_ASSERT(aRuns.PosIsInRun(6));
+
+ CPPUNIT_ASSERT(!aRuns.PosIsInRun(7));
+}
+
+void VclTextTest::testImplLayoutRuns_PosIsInAnyRun()
+{
+ ImplLayoutRuns aRuns;
+ aRuns.AddRun(1, 4, false);
+ aRuns.AddRun(4, 5, true);
+ aRuns.AddRun(5, 6, false);
+ aRuns.AddRun(6, 7, true);
+
+ CPPUNIT_ASSERT(aRuns.PosIsInAnyRun(1));
+ CPPUNIT_ASSERT(!aRuns.PosIsInAnyRun(7));
+}
+
void VclTextTest::testImplLayoutArgsBiDiStrong()
{
OUString sTestString = u"The quick brown fox\n jumped over the lazy dog"
diff --git a/vcl/source/gdi/sallayout.cxx b/vcl/source/gdi/sallayout.cxx
index debe3017a92a..7a69defd60f5 100644
--- a/vcl/source/gdi/sallayout.cxx
+++ b/vcl/source/gdi/sallayout.cxx
@@ -129,163 +129,6 @@ sal_UCS4 GetLocalizedChar( sal_UCS4 nChar, LanguageType eLang )
return nChar;
}
-void ImplLayoutRuns::AddPos( int nCharPos, bool bRTL )
-{
- // check if charpos could extend current run
- int nIndex = maRuns.size();
- if( nIndex >= 2 )
- {
- int nRunPos0 = maRuns[ nIndex-2 ];
- int nRunPos1 = maRuns[ nIndex-1 ];
- if( ((nCharPos + int(bRTL)) == nRunPos1) && ((nRunPos0 > nRunPos1) == bRTL) )
- {
- // extend current run by new charpos
- maRuns[ nIndex-1 ] = nCharPos + int(!bRTL);
- return;
- }
- // ignore new charpos when it is in current run
- if( (nRunPos0 <= nCharPos) && (nCharPos < nRunPos1) )
- return;
- if( (nRunPos1 <= nCharPos) && (nCharPos < nRunPos0) )
- return;
- }
-
- // else append a new run consisting of the new charpos
- maRuns.push_back( nCharPos + (bRTL ? 1 : 0) );
- maRuns.push_back( nCharPos + (bRTL ? 0 : 1) );
-}
-
-void ImplLayoutRuns::AddRun( int nCharPos0, int nCharPos1, bool bRTL )
-{
- if( nCharPos0 == nCharPos1 )
- return;
-
- // swap if needed
- if( bRTL == (nCharPos0 < nCharPos1) )
- {
- int nTemp = nCharPos0;
- nCharPos0 = nCharPos1;
- nCharPos1 = nTemp;
- }
-
- if (maRuns.size() >= 2 && nCharPos0 == maRuns[maRuns.size() - 2] && nCharPos1 == maRuns[maRuns.size() - 1])
- {
- //this run is the same as the last
- return;
- }
-
- // append new run
- maRuns.push_back( nCharPos0 );
- maRuns.push_back( nCharPos1 );
-}
-
-bool ImplLayoutRuns::PosIsInRun( int nCharPos ) const
-{
- if( mnRunIndex >= static_cast<int>(maRuns.size()) )
- return false;
-
- int nMinCharPos = maRuns[ mnRunIndex+0 ];
- int nEndCharPos = maRuns[ mnRunIndex+1 ];
- if( nMinCharPos > nEndCharPos ) // reversed in RTL case
- {
- int nTemp = nMinCharPos;
- nMinCharPos = nEndCharPos;
- nEndCharPos = nTemp;
- }
-
- if( nCharPos < nMinCharPos )
- return false;
- if( nCharPos >= nEndCharPos )
- return false;
- return true;
-}
-
-bool ImplLayoutRuns::PosIsInAnyRun( int nCharPos ) const
-{
- bool bRet = false;
- int nRunIndex = mnRunIndex;
-
- ImplLayoutRuns *pThis = const_cast<ImplLayoutRuns*>(this);
-
- pThis->ResetPos();
-
- for (size_t i = 0; i < maRuns.size(); i+=2)
- {
- bRet = PosIsInRun( nCharPos );
- if( bRet )
- break;
- pThis->NextRun();
- }
-
- pThis->mnRunIndex = nRunIndex;
- return bRet;
-}
-
-bool ImplLayoutRuns::GetNextPos( int* nCharPos, bool* bRightToLeft )
-{
- // negative nCharPos => reset to first run
- if( *nCharPos < 0 )
- mnRunIndex = 0;
-
- // return false when all runs completed
- if( mnRunIndex >= static_cast<int>(maRuns.size()) )
- return false;
-
- int nRunPos0 = maRuns[ mnRunIndex+0 ];
- int nRunPos1 = maRuns[ mnRunIndex+1 ];
- *bRightToLeft = (nRunPos0 > nRunPos1);
-
- if( *nCharPos < 0 )
- {
- // get first valid nCharPos in run
- *nCharPos = nRunPos0;
- }
- else
- {
- // advance to next nCharPos for LTR case
- if( !*bRightToLeft )
- ++(*nCharPos);
-
- // advance to next run if current run is completed
- if( *nCharPos == nRunPos1 )
- {
- if( (mnRunIndex += 2) >= static_cast<int>(maRuns.size()) )
- return false;
- nRunPos0 = maRuns[ mnRunIndex+0 ];
- nRunPos1 = maRuns[ mnRunIndex+1 ];
- *bRightToLeft = (nRunPos0 > nRunPos1);
- *nCharPos = nRunPos0;
- }
- }
-
- // advance to next nCharPos for RTL case
- if( *bRightToLeft )
- --(*nCharPos);
-
- return true;
-}
-
-bool ImplLayoutRuns::GetRun( int* nMinRunPos, int* nEndRunPos, bool* bRightToLeft ) const
-{
- if( mnRunIndex >= static_cast<int>(maRuns.size()) )
- return false;
-
- int nRunPos0 = maRuns[ mnRunIndex+0 ];
- int nRunPos1 = maRuns[ mnRunIndex+1 ];
- *bRightToLeft = (nRunPos1 < nRunPos0) ;
- if( !*bRightToLeft )
- {
- *nMinRunPos = nRunPos0;
- *nEndRunPos = nRunPos1;
- }
- else
- {
- *nMinRunPos = nRunPos1;
- *nEndRunPos = nRunPos0;
- }
- return true;
-}
-
SalLayout::SalLayout()
: mnMinCharPos( -1 ),
mnEndCharPos( -1 ),
diff --git a/vcl/source/text/ImplLayoutRuns.cxx b/vcl/source/text/ImplLayoutRuns.cxx
new file mode 100644
index 000000000000..a560e17e1b8b
--- /dev/null
+++ b/vcl/source/text/ImplLayoutRuns.cxx
@@ -0,0 +1,179 @@
+/* -*- 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 <ImplLayoutRuns.hxx>
+
+void ImplLayoutRuns::AddPos( int nCharPos, bool bRTL )
+{
+ // check if charpos could extend current run
+ int nIndex = maRuns.size();
+ if( nIndex >= 2 )
+ {
+ int nRunPos0 = maRuns[ nIndex-2 ];
+ int nRunPos1 = maRuns[ nIndex-1 ];
+ if( ((nCharPos + int(bRTL)) == nRunPos1) && ((nRunPos0 > nRunPos1) == bRTL) )
+ {
+ // extend current run by new charpos
+ maRuns[ nIndex-1 ] = nCharPos + int(!bRTL);
+ return;
+ }
+ // ignore new charpos when it is in current run
+ if( (nRunPos0 <= nCharPos) && (nCharPos < nRunPos1) )
+ return;
+ if( (nRunPos1 <= nCharPos) && (nCharPos < nRunPos0) )
+ return;
+ }
+
+ // else append a new run consisting of the new charpos
+ maRuns.push_back( nCharPos + (bRTL ? 1 : 0) );
+ maRuns.push_back( nCharPos + (bRTL ? 0 : 1) );
+}
+
+void ImplLayoutRuns::AddRun( int nCharPos0, int nCharPos1, bool bRTL )
+{
+ if( nCharPos0 == nCharPos1 )
+ return;
+
+ // swap if needed
+ if( bRTL == (nCharPos0 < nCharPos1) )
+ {
+ int nTemp = nCharPos0;
+ nCharPos0 = nCharPos1;
+ nCharPos1 = nTemp;
+ }
+
+ if (maRuns.size() >= 2 && nCharPos0 == maRuns[maRuns.size() - 2] && nCharPos1 == maRuns[maRuns.size() - 1])
+ {
+ //this run is the same as the last
+ return;
+ }
+
+ // append new run
+ maRuns.push_back( nCharPos0 );
+ maRuns.push_back( nCharPos1 );
+}
+
+bool ImplLayoutRuns::PosIsInRun( int nCharPos ) const
+{
+ if( mnRunIndex >= static_cast<int>(maRuns.size()) )
+ return false;
+
+ int nMinCharPos = maRuns[ mnRunIndex+0 ];
+ int nEndCharPos = maRuns[ mnRunIndex+1 ];
+ if( nMinCharPos > nEndCharPos ) // reversed in RTL case
+ {
+ int nTemp = nMinCharPos;
+ nMinCharPos = nEndCharPos;
+ nEndCharPos = nTemp;
+ }
+
+ if( nCharPos < nMinCharPos )
+ return false;
+ if( nCharPos >= nEndCharPos )
+ return false;
+ return true;
+}
+
+bool ImplLayoutRuns::PosIsInAnyRun( int nCharPos ) const
+{
+ bool bRet = false;
+ int nRunIndex = mnRunIndex;
+
+ ImplLayoutRuns *pThis = const_cast<ImplLayoutRuns*>(this);
+
+ pThis->ResetPos();
+
+ for (size_t i = 0; i < maRuns.size(); i+=2)
+ {
+ bRet = PosIsInRun( nCharPos );
+ if( bRet )
+ break;
+ pThis->NextRun();
+ }
+
+ pThis->mnRunIndex = nRunIndex;
+ return bRet;
+}
+
+bool ImplLayoutRuns::GetNextPos( int* nCharPos, bool* bRightToLeft )
+{
+ // negative nCharPos => reset to first run
+ if( *nCharPos < 0 )
+ mnRunIndex = 0;
+
+ // return false when all runs completed
+ if( mnRunIndex >= static_cast<int>(maRuns.size()) )
+ return false;
+
+ int nRunPos0 = maRuns[ mnRunIndex+0 ];
+ int nRunPos1 = maRuns[ mnRunIndex+1 ];
+ *bRightToLeft = (nRunPos0 > nRunPos1);
+
+ if( *nCharPos < 0 )
+ {
+ // get first valid nCharPos in run
+ *nCharPos = nRunPos0;
+ }
+ else
+ {
+ // advance to next nCharPos for LTR case
+ if( !*bRightToLeft )
+ ++(*nCharPos);
+
+ // advance to next run if current run is completed
+ if( *nCharPos == nRunPos1 )
+ {
+ if( (mnRunIndex += 2) >= static_cast<int>(maRuns.size()) )
+ return false;
+ nRunPos0 = maRuns[ mnRunIndex+0 ];
+ nRunPos1 = maRuns[ mnRunIndex+1 ];
+ *bRightToLeft = (nRunPos0 > nRunPos1);
+ *nCharPos = nRunPos0;
+ }
+ }
+
+ // advance to next nCharPos for RTL case
+ if( *bRightToLeft )
+ --(*nCharPos);
+
+ return true;
+}
+
+bool ImplLayoutRuns::GetRun( int* nMinRunPos, int* nEndRunPos, bool* bRightToLeft ) const
+{
+ if( mnRunIndex >= static_cast<int>(maRuns.size()) )
+ return false;
+
+ int nRunPos0 = maRuns[ mnRunIndex+0 ];
+ int nRunPos1 = maRuns[ mnRunIndex+1 ];
+ *bRightToLeft = (nRunPos1 < nRunPos0) ;
+ if( !*bRightToLeft )
+ {
+ *nMinRunPos = nRunPos0;
+ *nEndRunPos = nRunPos1;
+ }
+ else
+ {
+ *nMinRunPos = nRunPos1;
+ *nEndRunPos = nRunPos0;
+ }
+ return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */