summaryrefslogtreecommitdiffstats
path: root/svtools/source/control/scriptedtext.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /svtools/source/control/scriptedtext.cxx
parentInitial commit. (diff)
downloadlibreoffice-upstream.tar.xz
libreoffice-upstream.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'svtools/source/control/scriptedtext.cxx')
-rw-r--r--svtools/source/control/scriptedtext.cxx319
1 files changed, 319 insertions, 0 deletions
diff --git a/svtools/source/control/scriptedtext.cxx b/svtools/source/control/scriptedtext.cxx
new file mode 100644
index 000000000..18c6445b9
--- /dev/null
+++ b/svtools/source/control/scriptedtext.cxx
@@ -0,0 +1,319 @@
+/* -*- 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 <svtools/scriptedtext.hxx>
+#include <vector>
+#include <rtl/ustring.hxx>
+#include <vcl/outdev.hxx>
+#include <vcl/font.hxx>
+#include <tools/debug.hxx>
+#include <tools/gen.hxx>
+#include <com/sun/star/i18n/ScriptType.hpp>
+#include <com/sun/star/i18n/XBreakIterator.hpp>
+
+
+using namespace ::std;
+using namespace ::com::sun::star;
+
+
+class SvtScriptedTextHelper_Impl
+{
+private:
+ OutputDevice& mrOutDevice; /// The output device for drawing the text.
+ vcl::Font maLatinFont; /// The font for latin text portions.
+ vcl::Font maAsianFont; /// The font for asian text portions.
+ vcl::Font maCmplxFont; /// The font for complex text portions.
+ vcl::Font maDefltFont; /// The default font of the output device.
+ OUString maText; /// The text.
+
+ vector< sal_Int32 > maPosVec; /// The start position of each text portion.
+ vector< sal_Int16 > maScriptVec; /// The script type of each text portion.
+ vector< sal_Int32 > maWidthVec; /// The output width of each text portion.
+ Size maTextSize; /// The size the text will take in the current output device.
+
+ /** Gets the font of the given script type. */
+ const vcl::Font& GetFont( sal_uInt16 _nScript ) const;
+ /** Sets a font on the output device depending on the script type. */
+ void SetOutDevFont( sal_uInt16 _nScript )
+ { mrOutDevice.SetFont( GetFont( _nScript ) ); }
+ /** Fills maPosVec with positions of all changes of script type.
+ This method expects correctly initialized maPosVec and maScriptVec. */
+ void CalculateSizes();
+ /** Fills maPosVec with positions of all changes of script type and
+ maScriptVec with the script type of each portion. */
+ void CalculateBreaks(
+ const uno::Reference< i18n::XBreakIterator >& _xBreakIter );
+
+public:
+ /** This constructor sets an output device and fonts for all script types. */
+ explicit SvtScriptedTextHelper_Impl(
+ OutputDevice& _rOutDevice );
+
+ /** Sets new fonts and recalculates the text width. */
+ void SetFonts( vcl::Font const * _pLatinFont, vcl::Font const * _pAsianFont, vcl::Font const * _pCmplxFont );
+ /** Sets a new text and calculates all script breaks and the text width. */
+ void SetText(
+ const OUString& _rText,
+ const uno::Reference< i18n::XBreakIterator >& _xBreakIter );
+
+ /** Returns a size struct containing the width and height of the text in the current output device. */
+ const Size& GetTextSize() const { return maTextSize;}
+
+ /** Draws the text in the current output device. */
+ void DrawText( const Point& _rPos );
+};
+
+
+SvtScriptedTextHelper_Impl::SvtScriptedTextHelper_Impl(
+ OutputDevice& _rOutDevice ) :
+ mrOutDevice( _rOutDevice ),
+ maLatinFont( _rOutDevice.GetFont() ),
+ maAsianFont( _rOutDevice.GetFont() ),
+ maCmplxFont( _rOutDevice.GetFont() ),
+ maDefltFont( _rOutDevice.GetFont() )
+{
+}
+
+const vcl::Font& SvtScriptedTextHelper_Impl::GetFont( sal_uInt16 _nScript ) const
+{
+ switch( _nScript )
+ {
+ case i18n::ScriptType::LATIN: return maLatinFont;
+ case i18n::ScriptType::ASIAN: return maAsianFont;
+ case i18n::ScriptType::COMPLEX: return maCmplxFont;
+ }
+ return maDefltFont;
+}
+
+void SvtScriptedTextHelper_Impl::CalculateSizes()
+{
+ maTextSize.setWidth(0);
+ maTextSize.setHeight(0);
+ mrOutDevice.Push(vcl::PushFlags::FONT | vcl::PushFlags::TEXTCOLOR);
+
+ // calculate text portion widths and total width
+ maWidthVec.clear();
+ if( !maPosVec.empty() )
+ {
+ DBG_ASSERT( maPosVec.size() - 1 == maScriptVec.size(),
+ "SvtScriptedTextHelper_Impl::CalculateWidth - invalid vectors" );
+
+ sal_Int32 nThisPos = maPosVec[ 0 ];
+ sal_Int32 nNextPos;
+ sal_Int32 nPosVecSize = maPosVec.size();
+ sal_Int32 nPosVecIndex = 1;
+
+ sal_Int16 nScript;
+ sal_Int32 nScriptVecIndex = 0;
+
+ sal_Int32 nCurrWidth;
+
+ while( nPosVecIndex < nPosVecSize )
+ {
+ nNextPos = maPosVec[ nPosVecIndex++ ];
+ nScript = maScriptVec[ nScriptVecIndex++ ];
+
+ SetOutDevFont( nScript );
+ nCurrWidth = mrOutDevice.GetTextWidth( maText, nThisPos, nNextPos - nThisPos );
+ maWidthVec.push_back( nCurrWidth );
+ maTextSize.AdjustWidth(nCurrWidth );
+ nThisPos = nNextPos;
+ }
+ }
+
+ // calculate maximum font height
+ SetOutDevFont( i18n::ScriptType::LATIN );
+ maTextSize.setHeight( std::max( maTextSize.Height(), mrOutDevice.GetTextHeight() ) );
+ SetOutDevFont( i18n::ScriptType::ASIAN );
+ maTextSize.setHeight( std::max( maTextSize.Height(), mrOutDevice.GetTextHeight() ) );
+ SetOutDevFont( i18n::ScriptType::COMPLEX );
+ maTextSize.setHeight( std::max( maTextSize.Height(), mrOutDevice.GetTextHeight() ) );
+
+ mrOutDevice.Pop();
+}
+
+void SvtScriptedTextHelper_Impl::CalculateBreaks( const uno::Reference< i18n::XBreakIterator >& _xBreakIter )
+{
+ maPosVec.clear();
+ maScriptVec.clear();
+
+ DBG_ASSERT( _xBreakIter.is(), "SvtScriptedTextHelper_Impl::CalculateBreaks - no break iterator" );
+
+ sal_Int32 nLen = maText.getLength();
+ if( nLen )
+ {
+ if( _xBreakIter.is() )
+ {
+ sal_Int32 nThisPos = 0; // first position of this portion
+ sal_Int32 nNextPos = 0; // first position of next portion
+ sal_Int16 nPortScript; // script type of this portion
+ do
+ {
+ nPortScript = _xBreakIter->getScriptType( maText, nThisPos );
+ nNextPos = _xBreakIter->endOfScript( maText, nThisPos, nPortScript );
+
+ switch( nPortScript )
+ {
+ case i18n::ScriptType::LATIN:
+ case i18n::ScriptType::ASIAN:
+ case i18n::ScriptType::COMPLEX:
+ maPosVec.push_back( nThisPos );
+ maScriptVec.push_back( nPortScript );
+ break;
+ default:
+ {
+/* *** handling of weak characters ***
+- first portion is weak: Use OutputDevice::HasGlyphs() to find the correct font
+- weak portion follows another portion: Script type of preceding portion is used */
+ if( maPosVec.empty() )
+ {
+ sal_Int32 nCharIx = 0;
+ sal_Int32 nNextCharIx = 0;
+ sal_Int16 nScript;
+ do
+ {
+ nScript = i18n::ScriptType::LATIN;
+ while( (nScript != i18n::ScriptType::WEAK) && (nCharIx == nNextCharIx) )
+ {
+ nNextCharIx = mrOutDevice.HasGlyphs( GetFont( nScript ), maText, nCharIx, nNextPos - nCharIx );
+ if( nCharIx == nNextCharIx )
+ ++nScript;
+ }
+ if( nNextCharIx == nCharIx )
+ ++nNextCharIx;
+
+ maPosVec.push_back( nCharIx );
+ maScriptVec.push_back( nScript );
+ nCharIx = nNextCharIx;
+ }
+ while( nCharIx < nNextPos && nCharIx != -1 );
+ }
+ // nothing to do for following portions
+ }
+ }
+ nThisPos = nNextPos;
+ }
+ while( (0 <= nThisPos) && (nThisPos < nLen) );
+ }
+ else // no break iterator: whole text LATIN
+ {
+ maPosVec.push_back( 0 );
+ maScriptVec.push_back( i18n::ScriptType::LATIN );
+ }
+
+ // push end position of last portion
+ if( !maPosVec.empty() )
+ maPosVec.push_back( nLen );
+ }
+ CalculateSizes();
+}
+
+void SvtScriptedTextHelper_Impl::SetFonts( vcl::Font const * _pLatinFont, vcl::Font const * _pAsianFont, vcl::Font const * _pCmplxFont )
+{
+ maLatinFont = _pLatinFont ? *_pLatinFont : maDefltFont;
+ maAsianFont = _pAsianFont ? *_pAsianFont : maDefltFont;
+ maCmplxFont = _pCmplxFont ? *_pCmplxFont : maDefltFont;
+ CalculateSizes();
+}
+
+void SvtScriptedTextHelper_Impl::SetText( const OUString& _rText, const uno::Reference< i18n::XBreakIterator >& _xBreakIter )
+{
+ maText = _rText;
+ CalculateBreaks( _xBreakIter );
+}
+
+
+void SvtScriptedTextHelper_Impl::DrawText( const Point& _rPos )
+{
+ if( maText.isEmpty() || maPosVec.empty() )
+ return;
+
+ DBG_ASSERT( maPosVec.size() - 1 == maScriptVec.size(), "SvtScriptedTextHelper_Impl::DrawText - invalid vectors" );
+ DBG_ASSERT( maScriptVec.size() == maWidthVec.size(), "SvtScriptedTextHelper_Impl::DrawText - invalid vectors" );
+
+ mrOutDevice.Push(vcl::PushFlags::FONT | vcl::PushFlags::TEXTCOLOR);
+
+ Point aCurrPos( _rPos );
+ sal_Int32 nThisPos = maPosVec[ 0 ];
+ sal_Int32 nNextPos;
+ sal_Int32 nPosVecSize = maPosVec.size();
+ sal_Int32 nPosVecIndex = 1;
+
+ sal_Int16 nScript;
+ sal_Int32 nVecIndex = 0;
+
+ while( nPosVecIndex < nPosVecSize )
+ {
+ nNextPos = maPosVec[ nPosVecIndex++ ];
+ nScript = maScriptVec[ nVecIndex ];
+ vcl::Font aFont = GetFont( nScript );
+ mrOutDevice.SetFont( aFont );
+ if (aFont.GetColor() == COL_AUTO)
+ mrOutDevice.SetTextColor( mrOutDevice.GetFillColor().IsDark() ? COL_WHITE : COL_BLACK);
+ mrOutDevice.DrawText( aCurrPos, maText, nThisPos, nNextPos - nThisPos );
+ aCurrPos.AdjustX(maWidthVec[ nVecIndex++ ] );
+ aCurrPos.AdjustX(mrOutDevice.GetTextHeight() / 5 ); // add 20% of font height as portion spacing
+ nThisPos = nNextPos;
+ }
+
+ mrOutDevice.Pop();
+}
+
+
+SvtScriptedTextHelper::SvtScriptedTextHelper( OutputDevice& _rOutDevice ) :
+ mpImpl( new SvtScriptedTextHelper_Impl( _rOutDevice ) )
+{
+}
+
+SvtScriptedTextHelper::SvtScriptedTextHelper( const SvtScriptedTextHelper& _rCopy ) :
+ mpImpl( new SvtScriptedTextHelper_Impl( *_rCopy.mpImpl ) )
+{
+}
+
+SvtScriptedTextHelper::~SvtScriptedTextHelper()
+{
+}
+
+void SvtScriptedTextHelper::SetFonts( vcl::Font const * _pLatinFont, vcl::Font const * _pAsianFont, vcl::Font const * _pCmplxFont )
+{
+ mpImpl->SetFonts( _pLatinFont, _pAsianFont, _pCmplxFont );
+}
+
+void SvtScriptedTextHelper::SetDefaultFont()
+{
+ mpImpl->SetFonts( nullptr, nullptr, nullptr );
+}
+
+void SvtScriptedTextHelper::SetText( const OUString& _rText, const uno::Reference< i18n::XBreakIterator >& _xBreakIter )
+{
+ mpImpl->SetText( _rText, _xBreakIter );
+}
+
+const Size& SvtScriptedTextHelper::GetTextSize() const
+{
+ return mpImpl->GetTextSize();
+}
+
+void SvtScriptedTextHelper::DrawText( const Point& _rPos )
+{
+ mpImpl->DrawText( _rPos );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */