blob: a882572dc1537156d4b56163f5454523a197e77f [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_drawinglayer.hxx"
#include <drawinglayer/primitive2d/textbreakuphelper.hxx>
#include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
#include <com/sun/star/i18n/XBreakIterator.hpp>
#include <comphelper/processfactory.hxx>
#include <com/sun/star/i18n/CharacterIteratorMode.hdl>
#include <com/sun/star/i18n/WordType.hpp>
#include <com/sun/star/i18n/CharType.hpp>
//////////////////////////////////////////////////////////////////////////////
namespace drawinglayer
{
namespace primitive2d
{
TextBreakupHelper::TextBreakupHelper(const TextSimplePortionPrimitive2D& rSource)
: mrSource(rSource),
mxResult(),
maTextLayouter(),
maDecTrans(),
mbNoDXArray(false)
{
OSL_ENSURE(dynamic_cast< const TextSimplePortionPrimitive2D* >(&mrSource), "TextBreakupHelper with illegal primitive created (!)");
maDecTrans = mrSource.getTextTransform();
mbNoDXArray = mrSource.getDXArray().empty();
if(mbNoDXArray)
{
// init TextLayouter when no dxarray
maTextLayouter.setFontAttribute(
mrSource.getFontAttribute(),
maDecTrans.getScale().getX(),
maDecTrans.getScale().getY(),
mrSource.getLocale());
}
}
TextBreakupHelper::~TextBreakupHelper()
{
}
void TextBreakupHelper::breakupPortion(Primitive2DVector& rTempResult, sal_uInt32 nIndex, sal_uInt32 nLength, bool bWordLineMode)
{
if(nLength && !(nIndex == mrSource.getTextPosition() && nLength == mrSource.getTextLength()))
{
// prepare values for new portion
basegfx::B2DHomMatrix aNewTransform;
::std::vector< double > aNewDXArray;
const bool bNewStartIsNotOldStart(nIndex > mrSource.getTextPosition());
if(!mbNoDXArray)
{
// prepare new DXArray for the single word
aNewDXArray = ::std::vector< double >(
mrSource.getDXArray().begin() + (nIndex - mrSource.getTextPosition()),
mrSource.getDXArray().begin() + ((nIndex + nLength) - mrSource.getTextPosition()));
}
if(bNewStartIsNotOldStart)
{
// needs to be moved to a new start position
double fOffset(0.0);
if(mbNoDXArray)
{
// evaluate using TextLayouter
fOffset = maTextLayouter.getTextWidth(mrSource.getText(), mrSource.getTextPosition(), nIndex);
}
else
{
// get from DXArray
const sal_uInt32 nIndex2(static_cast< sal_uInt32 >(nIndex - mrSource.getTextPosition()));
fOffset = mrSource.getDXArray()[nIndex2 - 1];
}
// need offset without FontScale for building the new transformation. The
// new transformation will be multiplied with the current text transformation
// so FontScale would be double
double fOffsetNoScale(fOffset);
const double fFontScaleX(maDecTrans.getScale().getX());
if(!basegfx::fTools::equal(fFontScaleX, 1.0)
&& !basegfx::fTools::equalZero(fFontScaleX))
{
fOffsetNoScale /= fFontScaleX;
}
// apply needed offset to transformation
aNewTransform.translate(fOffsetNoScale, 0.0);
if(!mbNoDXArray)
{
// DXArray values need to be corrected with the offset, too. Here,
// take the scaled offset since the DXArray is scaled
const sal_uInt32 nArraySize(aNewDXArray.size());
for(sal_uInt32 a(0); a < nArraySize; a++)
{
aNewDXArray[a] -= fOffset;
}
}
}
// add text transformation to new transformation
aNewTransform = maDecTrans.getB2DHomMatrix() * aNewTransform;
// callback to allow evtl. changes
const bool bCreate(allowChange(rTempResult.size(), aNewTransform, nIndex, nLength));
if(bCreate)
{
// check if we have a decorated primitive as source
const TextDecoratedPortionPrimitive2D* pTextDecoratedPortionPrimitive2D =
dynamic_cast< const TextDecoratedPortionPrimitive2D* >(&mrSource);
if(pTextDecoratedPortionPrimitive2D)
{
// create a TextDecoratedPortionPrimitive2D
rTempResult.push_back(
new TextDecoratedPortionPrimitive2D(
aNewTransform,
mrSource.getText(),
nIndex,
nLength,
aNewDXArray,
mrSource.getFontAttribute(),
mrSource.getLocale(),
mrSource.getFontColor(),
pTextDecoratedPortionPrimitive2D->getOverlineColor(),
pTextDecoratedPortionPrimitive2D->getTextlineColor(),
pTextDecoratedPortionPrimitive2D->getFontOverline(),
pTextDecoratedPortionPrimitive2D->getFontUnderline(),
pTextDecoratedPortionPrimitive2D->getUnderlineAbove(),
pTextDecoratedPortionPrimitive2D->getTextStrikeout(),
// reset WordLineMode when BreakupUnit_word is executed; else copy original
bWordLineMode ? false : pTextDecoratedPortionPrimitive2D->getWordLineMode(),
pTextDecoratedPortionPrimitive2D->getTextEmphasisMark(),
pTextDecoratedPortionPrimitive2D->getEmphasisMarkAbove(),
pTextDecoratedPortionPrimitive2D->getEmphasisMarkBelow(),
pTextDecoratedPortionPrimitive2D->getTextRelief(),
pTextDecoratedPortionPrimitive2D->getShadow()));
}
else
{
// create a SimpleTextPrimitive
rTempResult.push_back(
new TextSimplePortionPrimitive2D(
aNewTransform,
mrSource.getText(),
nIndex,
nLength,
aNewDXArray,
mrSource.getFontAttribute(),
mrSource.getLocale(),
mrSource.getFontColor()));
}
}
}
}
bool TextBreakupHelper::allowChange(sal_uInt32 /*nCount*/, basegfx::B2DHomMatrix& /*rNewTransform*/, sal_uInt32 /*nIndex*/, sal_uInt32 /*nLength*/)
{
return true;
}
void TextBreakupHelper::breakup(BreakupUnit aBreakupUnit)
{
if(mrSource.getTextLength())
{
Primitive2DVector aTempResult;
static ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > xBreakIterator;
if(!xBreakIterator.is())
{
::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF(::comphelper::getProcessServiceFactory());
xBreakIterator.set(xMSF->createInstance(rtl::OUString::createFromAscii("com.sun.star.i18n.BreakIterator")), ::com::sun::star::uno::UNO_QUERY);
}
if(xBreakIterator.is())
{
const rtl::OUString& rTxt = mrSource.getText();
const sal_Int32 nTextLength(mrSource.getTextLength());
const ::com::sun::star::lang::Locale& rLocale = mrSource.getLocale();
const sal_Int32 nTextPosition(mrSource.getTextPosition());
sal_Int32 nCurrent(nTextPosition);
switch(aBreakupUnit)
{
case BreakupUnit_character:
{
sal_Int32 nDone;
sal_Int32 nNextCellBreak(xBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone));
sal_Int32 a(nTextPosition);
for(; a < nTextPosition + nTextLength; a++)
{
if(a == nNextCellBreak)
{
breakupPortion(aTempResult, nCurrent, a - nCurrent, false);
nCurrent = a;
nNextCellBreak = xBreakIterator->nextCharacters(rTxt, a, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
}
}
breakupPortion(aTempResult, nCurrent, a - nCurrent, false);
break;
}
case BreakupUnit_word:
{
::com::sun::star::i18n::Boundary nNextWordBoundary(xBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True));
sal_Int32 a(nTextPosition);
for(; a < nTextPosition + nTextLength; a++)
{
if(a == nNextWordBoundary.endPos)
{
if(a > nCurrent)
{
breakupPortion(aTempResult, nCurrent, a - nCurrent, true);
}
nCurrent = a;
// skip spaces (maybe enhanced with a bool later if needed)
{
const sal_Int32 nEndOfSpaces(xBreakIterator->endOfCharBlock(rTxt, a, rLocale, ::com::sun::star::i18n::CharType::SPACE_SEPARATOR));
if(nEndOfSpaces > a)
{
nCurrent = nEndOfSpaces;
}
}
nNextWordBoundary = xBreakIterator->getWordBoundary(rTxt, a + 1, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True);
}
}
if(a > nCurrent)
{
breakupPortion(aTempResult, nCurrent, a - nCurrent, true);
}
break;
}
case BreakupUnit_sentence:
{
sal_Int32 nNextSentenceBreak(xBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale));
sal_Int32 a(nTextPosition);
for(; a < nTextPosition + nTextLength; a++)
{
if(a == nNextSentenceBreak)
{
breakupPortion(aTempResult, nCurrent, a - nCurrent, false);
nCurrent = a;
nNextSentenceBreak = xBreakIterator->endOfSentence(rTxt, a + 1, rLocale);
}
}
breakupPortion(aTempResult, nCurrent, a - nCurrent, false);
break;
}
}
}
mxResult = Primitive2DVectorToPrimitive2DSequence(aTempResult);
}
}
const Primitive2DSequence& TextBreakupHelper::getResult(BreakupUnit aBreakupUnit) const
{
if(!mxResult.hasElements())
{
const_cast< TextBreakupHelper* >(this)->breakup(aBreakupUnit);
}
return mxResult;
}
} // end of namespace primitive2d
} // end of namespace drawinglayer
//////////////////////////////////////////////////////////////////////////////
// eof