/************************************************************** * * 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 #include #include #include #include #include #include ////////////////////////////////////////////////////////////////////////////// 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