office-gobmx/drawinglayer/source/primitive2d/textbreakuphelper.cxx
Noel Grandin ead920a48a loplugin:redundantcast handle dynamic_cast
Change-Id: I7855c76e820efce96778b1c19ec71dffcc4b4abb
Reviewed-on: https://gerrit.libreoffice.org/43621
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
2017-10-21 15:44:11 +02:00

281 lines
12 KiB
C++

/* -*- 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 <drawinglayer/primitive2d/textbreakuphelper.hxx>
#include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
#include <com/sun/star/i18n/BreakIterator.hpp>
#include <comphelper/processfactory.hxx>
#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
#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)
{
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(Primitive2DContainer& rTempResult, sal_Int32 nIndex, sal_Int32 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_Int32 nIndex2(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(),
mrSource.getTextFillColor(),
pTextDecoratedPortionPrimitive2D->getOverlineColor(),
pTextDecoratedPortionPrimitive2D->getTextlineColor(),
pTextDecoratedPortionPrimitive2D->getFontOverline(),
pTextDecoratedPortionPrimitive2D->getFontUnderline(),
pTextDecoratedPortionPrimitive2D->getUnderlineAbove(),
pTextDecoratedPortionPrimitive2D->getTextStrikeout(),
// reset WordLineMode when BreakupUnit::Word is executed; else copy original
!bWordLineMode && 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())
{
Primitive2DContainer aTempResult;
static css::uno::Reference< css::i18n::XBreakIterator > xBreakIterator;
if(!xBreakIterator.is())
{
css::uno::Reference< css::uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
xBreakIterator = css::i18n::BreakIterator::create(xContext);
}
const OUString& rTxt = mrSource.getText();
const sal_Int32 nTextLength(mrSource.getTextLength());
const css::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, css::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, css::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
}
}
breakupPortion(aTempResult, nCurrent, a - nCurrent, false);
break;
}
case BreakupUnit::Word:
{
css::i18n::Boundary nNextWordBoundary(xBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, css::i18n::WordType::ANY_WORD, 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, css::i18n::CharType::SPACE_SEPARATOR));
if(nEndOfSpaces > a)
{
nCurrent = nEndOfSpaces;
}
}
nNextWordBoundary = xBreakIterator->getWordBoundary(rTxt, a + 1, rLocale, css::i18n::WordType::ANY_WORD, true);
}
}
if(a > nCurrent)
{
breakupPortion(aTempResult, nCurrent, a - nCurrent, true);
}
break;
}
}
mxResult = aTempResult;
}
}
const Primitive2DContainer& TextBreakupHelper::getResult(BreakupUnit aBreakupUnit) const
{
if(mxResult.empty())
{
const_cast< TextBreakupHelper* >(this)->breakup(aBreakupUnit);
}
return mxResult;
}
} // end of namespace primitive2d
} // end of namespace drawinglayer
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */