f9a0fa94f2
Change-Id: Icb84c34782dd41e0658f5f8ed4f689f149331d99
607 lines
28 KiB
C++
607 lines
28 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2000, 2010 Oracle and/or its affiliates.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
* only, as published by the Free Software Foundation.
|
|
*
|
|
* OpenOffice.org is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License version 3 for more details
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 License.
|
|
*
|
|
************************************************************************/
|
|
|
|
#include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
|
|
#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
|
|
#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
|
|
#include <drawinglayer/attribute/strokeattribute.hxx>
|
|
#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
|
|
#include <basegfx/matrix/b2dhommatrixtools.hxx>
|
|
#include <comphelper/processfactory.hxx>
|
|
#include <com/sun/star/i18n/WordType.hpp>
|
|
#include <drawinglayer/primitive2d/texteffectprimitive2d.hxx>
|
|
#include <drawinglayer/primitive2d/shadowprimitive2d.hxx>
|
|
#include <com/sun/star/i18n/XBreakIterator.hpp>
|
|
#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
|
|
#include <drawinglayer/primitive2d/textlineprimitive2d.hxx>
|
|
#include <drawinglayer/primitive2d/textstrikeoutprimitive2d.hxx>
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
namespace drawinglayer
|
|
{
|
|
namespace primitive2d
|
|
{
|
|
void TextDecoratedPortionPrimitive2D::impCreateGeometryContent(
|
|
std::vector< Primitive2DReference >& rTarget,
|
|
basegfx::tools::B2DHomMatrixBufferedOnDemandDecompose& rDecTrans,
|
|
const String& rText,
|
|
xub_StrLen aTextPosition,
|
|
xub_StrLen aTextLength,
|
|
const ::std::vector< double >& rDXArray,
|
|
const attribute::FontAttribute& rFontAttribute) const
|
|
{
|
|
// create the SimpleTextPrimitive needed in any case
|
|
rTarget.push_back(Primitive2DReference(
|
|
new TextSimplePortionPrimitive2D(
|
|
rDecTrans.getB2DHomMatrix(),
|
|
rText,
|
|
aTextPosition,
|
|
aTextLength,
|
|
rDXArray,
|
|
rFontAttribute,
|
|
getLocale(),
|
|
getFontColor())));
|
|
|
|
// see if something else needs to be done
|
|
const bool bOverlineUsed(TEXT_LINE_NONE != getFontOverline());
|
|
const bool bUnderlineUsed(TEXT_LINE_NONE != getFontUnderline());
|
|
const bool bStrikeoutUsed(TEXT_STRIKEOUT_NONE != getTextStrikeout());
|
|
|
|
if(bUnderlineUsed || bStrikeoutUsed || bOverlineUsed)
|
|
{
|
|
// common preparations
|
|
TextLayouterDevice aTextLayouter;
|
|
|
|
// TextLayouterDevice is needed to get metrics for text decorations like
|
|
// underline/strikeout/emphasis marks from it. For setup, the font size is needed
|
|
aTextLayouter.setFontAttribute(
|
|
getFontAttribute(),
|
|
rDecTrans.getScale().getX(),
|
|
rDecTrans.getScale().getY(),
|
|
getLocale());
|
|
|
|
// get text width
|
|
double fTextWidth(0.0);
|
|
|
|
if(rDXArray.empty())
|
|
{
|
|
fTextWidth = aTextLayouter.getTextWidth(rText, aTextPosition, aTextLength);
|
|
}
|
|
else
|
|
{
|
|
fTextWidth = rDXArray.back() * rDecTrans.getScale().getX();
|
|
const double fFontScaleX(rDecTrans.getScale().getX());
|
|
|
|
if(!basegfx::fTools::equal(fFontScaleX, 1.0)
|
|
&& !basegfx::fTools::equalZero(fFontScaleX))
|
|
{
|
|
// need to take FontScaling out of the DXArray
|
|
fTextWidth /= fFontScaleX;
|
|
}
|
|
}
|
|
|
|
if(bOverlineUsed)
|
|
{
|
|
// create primitive geometry for overline
|
|
rTarget.push_back(Primitive2DReference(
|
|
new TextLinePrimitive2D(
|
|
rDecTrans.getB2DHomMatrix(),
|
|
fTextWidth,
|
|
aTextLayouter.getOverlineOffset(),
|
|
aTextLayouter.getOverlineHeight(),
|
|
getFontOverline(),
|
|
getOverlineColor())));
|
|
}
|
|
|
|
if(bUnderlineUsed)
|
|
{
|
|
// create primitive geometry for underline
|
|
rTarget.push_back(Primitive2DReference(
|
|
new TextLinePrimitive2D(
|
|
rDecTrans.getB2DHomMatrix(),
|
|
fTextWidth,
|
|
aTextLayouter.getUnderlineOffset(),
|
|
aTextLayouter.getUnderlineHeight(),
|
|
getFontUnderline(),
|
|
getTextlineColor())));
|
|
}
|
|
|
|
if(bStrikeoutUsed)
|
|
{
|
|
// create primitive geometry for strikeout
|
|
if(TEXT_STRIKEOUT_SLASH == getTextStrikeout() || TEXT_STRIKEOUT_X == getTextStrikeout())
|
|
{
|
|
// strikeout with character
|
|
const sal_Unicode aStrikeoutChar(TEXT_STRIKEOUT_SLASH == getTextStrikeout() ? '/' : 'X');
|
|
|
|
rTarget.push_back(Primitive2DReference(
|
|
new TextCharacterStrikeoutPrimitive2D(
|
|
rDecTrans.getB2DHomMatrix(),
|
|
fTextWidth,
|
|
getFontColor(),
|
|
aStrikeoutChar,
|
|
getFontAttribute(),
|
|
getLocale())));
|
|
}
|
|
else
|
|
{
|
|
// strikeout with geometry
|
|
rTarget.push_back(Primitive2DReference(
|
|
new TextGeometryStrikeoutPrimitive2D(
|
|
rDecTrans.getB2DHomMatrix(),
|
|
fTextWidth,
|
|
getFontColor(),
|
|
aTextLayouter.getUnderlineHeight(),
|
|
aTextLayouter.getStrikeoutOffset(),
|
|
getTextStrikeout())));
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: Handle Font Emphasis Above/Below
|
|
}
|
|
|
|
void TextDecoratedPortionPrimitive2D::impCorrectTextBoundary(::com::sun::star::i18n::Boundary& rNextWordBoundary) const
|
|
{
|
|
// truncate aNextWordBoundary to min/max possible values. This is necessary since the word start may be
|
|
// before/after getTextPosition() when a long string is the content and getTextPosition()
|
|
// is right inside a word. Same for end.
|
|
const sal_Int32 aMinPos(static_cast< sal_Int32 >(getTextPosition()));
|
|
const sal_Int32 aMaxPos(aMinPos + static_cast< sal_Int32 >(getTextLength()));
|
|
|
|
if(rNextWordBoundary.startPos < aMinPos)
|
|
{
|
|
rNextWordBoundary.startPos = aMinPos;
|
|
}
|
|
else if(rNextWordBoundary.startPos > aMaxPos)
|
|
{
|
|
rNextWordBoundary.startPos = aMaxPos;
|
|
}
|
|
|
|
if(rNextWordBoundary.endPos < aMinPos)
|
|
{
|
|
rNextWordBoundary.endPos = aMinPos;
|
|
}
|
|
else if(rNextWordBoundary.endPos > aMaxPos)
|
|
{
|
|
rNextWordBoundary.endPos = aMaxPos;
|
|
}
|
|
}
|
|
|
|
void TextDecoratedPortionPrimitive2D::impSplitSingleWords(
|
|
std::vector< Primitive2DReference >& rTarget,
|
|
basegfx::tools::B2DHomMatrixBufferedOnDemandDecompose& rDecTrans) const
|
|
{
|
|
// break iterator support
|
|
// made static so it only needs to be fetched once, even with many single
|
|
// constructed VclMetafileProcessor2D. It's still incarnated on demand,
|
|
// but exists for OOo runtime now by purpose.
|
|
static ::com::sun::star::uno::Reference< ::com::sun::star::i18n::XBreakIterator > xLocalBreakIterator;
|
|
|
|
if(!xLocalBreakIterator.is())
|
|
{
|
|
::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF(::comphelper::getProcessServiceFactory());
|
|
xLocalBreakIterator.set(xMSF->createInstance("com.sun.star.i18n.BreakIterator"), ::com::sun::star::uno::UNO_QUERY);
|
|
}
|
|
|
|
if(xLocalBreakIterator.is() && getTextLength())
|
|
{
|
|
// init word iterator, get first word and truncate to possibilities
|
|
::com::sun::star::i18n::Boundary aNextWordBoundary(xLocalBreakIterator->getWordBoundary(
|
|
getText(), getTextPosition(), getLocale(), ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True));
|
|
|
|
if(aNextWordBoundary.endPos == getTextPosition())
|
|
{
|
|
// backward hit, force next word
|
|
aNextWordBoundary = xLocalBreakIterator->getWordBoundary(
|
|
getText(), getTextPosition() + 1, getLocale(), ::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True);
|
|
}
|
|
|
|
impCorrectTextBoundary(aNextWordBoundary);
|
|
|
|
// prepare new font attributes WITHOUT outline
|
|
const attribute::FontAttribute aNewFontAttribute(
|
|
getFontAttribute().getFamilyName(),
|
|
getFontAttribute().getStyleName(),
|
|
getFontAttribute().getWeight(),
|
|
getFontAttribute().getSymbol(),
|
|
getFontAttribute().getVertical(),
|
|
getFontAttribute().getItalic(),
|
|
getFontAttribute().getMonospaced(),
|
|
false, // no outline anymore, handled locally
|
|
getFontAttribute().getRTL(),
|
|
getFontAttribute().getBiDiStrong());
|
|
|
|
if(aNextWordBoundary.startPos == getTextPosition() && aNextWordBoundary.endPos == getTextLength())
|
|
{
|
|
// it IS only a single word, handle as one word
|
|
impCreateGeometryContent(rTarget, rDecTrans, getText(), getTextPosition(), getTextLength(), getDXArray(), aNewFontAttribute);
|
|
}
|
|
else
|
|
{
|
|
// prepare TextLayouter
|
|
const bool bNoDXArray(getDXArray().empty());
|
|
TextLayouterDevice aTextLayouter;
|
|
|
|
if(bNoDXArray)
|
|
{
|
|
// ..but only completely when no DXArray
|
|
aTextLayouter.setFontAttribute(
|
|
getFontAttribute(),
|
|
rDecTrans.getScale().getX(),
|
|
rDecTrans.getScale().getY(),
|
|
getLocale());
|
|
}
|
|
|
|
// do iterate over single words
|
|
while(aNextWordBoundary.startPos != aNextWordBoundary.endPos)
|
|
{
|
|
// prepare values for new portion
|
|
const xub_StrLen nNewTextStart(static_cast< xub_StrLen >(aNextWordBoundary.startPos));
|
|
const xub_StrLen nNewTextEnd(static_cast< xub_StrLen >(aNextWordBoundary.endPos));
|
|
|
|
// prepare transform for the single word
|
|
basegfx::B2DHomMatrix aNewTransform;
|
|
::std::vector< double > aNewDXArray;
|
|
const bool bNewStartIsNotOldStart(nNewTextStart > getTextPosition());
|
|
|
|
if(!bNoDXArray)
|
|
{
|
|
// prepare new DXArray for the single word
|
|
aNewDXArray = ::std::vector< double >(
|
|
getDXArray().begin() + static_cast< sal_uInt32 >(nNewTextStart - getTextPosition()),
|
|
getDXArray().begin() + static_cast< sal_uInt32 >(nNewTextEnd - getTextPosition()));
|
|
}
|
|
|
|
if(bNewStartIsNotOldStart)
|
|
{
|
|
// needs to be moved to a new start position
|
|
double fOffset(0.0);
|
|
|
|
if(bNoDXArray)
|
|
{
|
|
// evaluate using TextLayouter
|
|
fOffset = aTextLayouter.getTextWidth(getText(), getTextPosition(), nNewTextStart);
|
|
}
|
|
else
|
|
{
|
|
// get from DXArray
|
|
const sal_uInt32 nIndex(static_cast< sal_uInt32 >(nNewTextStart - getTextPosition()));
|
|
fOffset = getDXArray()[nIndex - 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(rDecTrans.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(!bNoDXArray)
|
|
{
|
|
// 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 *= rDecTrans.getB2DHomMatrix();
|
|
|
|
// create geometry content for the single word. Do not forget
|
|
// to use the new transformation
|
|
basegfx::tools::B2DHomMatrixBufferedOnDemandDecompose aDecTrans(aNewTransform);
|
|
|
|
impCreateGeometryContent(rTarget, aDecTrans, getText(), nNewTextStart,
|
|
nNewTextEnd - nNewTextStart, aNewDXArray, aNewFontAttribute);
|
|
|
|
if(aNextWordBoundary.endPos >= getTextPosition() + getTextLength())
|
|
{
|
|
// end reached
|
|
aNextWordBoundary.startPos = aNextWordBoundary.endPos;
|
|
}
|
|
else
|
|
{
|
|
// get new word portion
|
|
const sal_Int32 nLastEndPos(aNextWordBoundary.endPos);
|
|
|
|
aNextWordBoundary = xLocalBreakIterator->getWordBoundary(
|
|
getText(), aNextWordBoundary.endPos, getLocale(),
|
|
::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True);
|
|
|
|
if(nLastEndPos == aNextWordBoundary.endPos)
|
|
{
|
|
// backward hit, force next word
|
|
aNextWordBoundary = xLocalBreakIterator->getWordBoundary(
|
|
getText(), nLastEndPos + 1, getLocale(),
|
|
::com::sun::star::i18n::WordType::ANYWORD_IGNOREWHITESPACES, sal_True);
|
|
}
|
|
|
|
impCorrectTextBoundary(aNextWordBoundary);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Primitive2DSequence TextDecoratedPortionPrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
|
|
{
|
|
std::vector< Primitive2DReference > aNewPrimitives;
|
|
basegfx::tools::B2DHomMatrixBufferedOnDemandDecompose aDecTrans(getTextTransform());
|
|
Primitive2DSequence aRetval;
|
|
|
|
// create basic geometry such as SimpleTextPrimitive, Overline, Underline,
|
|
// Strikeout, etc...
|
|
if(getWordLineMode())
|
|
{
|
|
// support for single word mode
|
|
impSplitSingleWords(aNewPrimitives, aDecTrans);
|
|
}
|
|
else
|
|
{
|
|
// prepare new font attributes WITHOUT outline
|
|
const attribute::FontAttribute aNewFontAttribute(
|
|
getFontAttribute().getFamilyName(),
|
|
getFontAttribute().getStyleName(),
|
|
getFontAttribute().getWeight(),
|
|
getFontAttribute().getSymbol(),
|
|
getFontAttribute().getVertical(),
|
|
getFontAttribute().getItalic(),
|
|
false, // no outline anymore, handled locally
|
|
getFontAttribute().getRTL(),
|
|
getFontAttribute().getBiDiStrong());
|
|
|
|
// handle as one word
|
|
impCreateGeometryContent(aNewPrimitives, aDecTrans, getText(), getTextPosition(), getTextLength(), getDXArray(), aNewFontAttribute);
|
|
}
|
|
|
|
// convert to Primitive2DSequence
|
|
const sal_uInt32 nMemberCount(aNewPrimitives.size());
|
|
|
|
if(nMemberCount)
|
|
{
|
|
aRetval.realloc(nMemberCount);
|
|
|
|
for(sal_uInt32 a(0); a < nMemberCount; a++)
|
|
{
|
|
aRetval[a] = aNewPrimitives[a];
|
|
}
|
|
}
|
|
|
|
// Handle Shadow, Outline and TextRelief
|
|
if(aRetval.hasElements())
|
|
{
|
|
// outline AND shadow depend on NO TextRelief (see dialog)
|
|
const bool bHasTextRelief(TEXT_RELIEF_NONE != getTextRelief());
|
|
const bool bHasShadow(!bHasTextRelief && getShadow());
|
|
const bool bHasOutline(!bHasTextRelief && getFontAttribute().getOutline());
|
|
|
|
if(bHasShadow || bHasTextRelief || bHasOutline)
|
|
{
|
|
Primitive2DReference aShadow;
|
|
|
|
if(bHasShadow)
|
|
{
|
|
// create shadow with current content (in aRetval). Text shadow
|
|
// is constant, relative to font size, rotated with the text and has a
|
|
// constant color.
|
|
// shadow parameter values
|
|
static double fFactor(1.0 / 24.0);
|
|
const double fTextShadowOffset(aDecTrans.getScale().getY() * fFactor);
|
|
static basegfx::BColor aShadowColor(0.3, 0.3, 0.3);
|
|
|
|
// preapare shadow transform matrix
|
|
const basegfx::B2DHomMatrix aShadowTransform(basegfx::tools::createTranslateB2DHomMatrix(
|
|
fTextShadowOffset, fTextShadowOffset));
|
|
|
|
// create shadow primitive
|
|
aShadow = Primitive2DReference(new ShadowPrimitive2D(
|
|
aShadowTransform,
|
|
aShadowColor,
|
|
aRetval));
|
|
}
|
|
|
|
if(bHasTextRelief)
|
|
{
|
|
// create emboss using an own helper primitive since this will
|
|
// be view-dependent
|
|
const basegfx::BColor aBBlack(0.0, 0.0, 0.0);
|
|
const bool bDefaultTextColor(aBBlack == getFontColor());
|
|
TextEffectStyle2D aTextEffectStyle2D(TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED);
|
|
|
|
if(bDefaultTextColor)
|
|
{
|
|
if(TEXT_RELIEF_ENGRAVED == getTextRelief())
|
|
{
|
|
aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED_DEFAULT;
|
|
}
|
|
else
|
|
{
|
|
aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED_DEFAULT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(TEXT_RELIEF_ENGRAVED == getTextRelief())
|
|
{
|
|
aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_ENGRAVED;
|
|
}
|
|
else
|
|
{
|
|
aTextEffectStyle2D = TEXTEFFECTSTYLE2D_RELIEF_EMBOSSED;
|
|
}
|
|
}
|
|
|
|
Primitive2DReference aNewTextEffect(new TextEffectPrimitive2D(
|
|
aRetval,
|
|
aDecTrans.getTranslate(),
|
|
aDecTrans.getRotate(),
|
|
aTextEffectStyle2D));
|
|
aRetval = Primitive2DSequence(&aNewTextEffect, 1);
|
|
}
|
|
else if(bHasOutline)
|
|
{
|
|
// create outline using an own helper primitive since this will
|
|
// be view-dependent
|
|
Primitive2DReference aNewTextEffect(new TextEffectPrimitive2D(
|
|
aRetval,
|
|
aDecTrans.getTranslate(),
|
|
aDecTrans.getRotate(),
|
|
TEXTEFFECTSTYLE2D_OUTLINE));
|
|
aRetval = Primitive2DSequence(&aNewTextEffect, 1);
|
|
}
|
|
|
|
if(aShadow.is())
|
|
{
|
|
// put shadow in front if there is one to paint timely before
|
|
// but placed behind content
|
|
const Primitive2DSequence aContent(aRetval);
|
|
aRetval = Primitive2DSequence(&aShadow, 1);
|
|
appendPrimitive2DSequenceToPrimitive2DSequence(aRetval, aContent);
|
|
}
|
|
}
|
|
}
|
|
|
|
return aRetval;
|
|
}
|
|
|
|
TextDecoratedPortionPrimitive2D::TextDecoratedPortionPrimitive2D(
|
|
|
|
// TextSimplePortionPrimitive2D parameters
|
|
const basegfx::B2DHomMatrix& rNewTransform,
|
|
const String& rText,
|
|
xub_StrLen aTextPosition,
|
|
xub_StrLen aTextLength,
|
|
const ::std::vector< double >& rDXArray,
|
|
const attribute::FontAttribute& rFontAttribute,
|
|
const ::com::sun::star::lang::Locale& rLocale,
|
|
const basegfx::BColor& rFontColor,
|
|
|
|
// local parameters
|
|
const basegfx::BColor& rOverlineColor,
|
|
const basegfx::BColor& rTextlineColor,
|
|
TextLine eFontOverline,
|
|
TextLine eFontUnderline,
|
|
bool bUnderlineAbove,
|
|
TextStrikeout eTextStrikeout,
|
|
bool bWordLineMode,
|
|
TextEmphasisMark eTextEmphasisMark,
|
|
bool bEmphasisMarkAbove,
|
|
bool bEmphasisMarkBelow,
|
|
TextRelief eTextRelief,
|
|
bool bShadow)
|
|
: TextSimplePortionPrimitive2D(rNewTransform, rText, aTextPosition, aTextLength, rDXArray, rFontAttribute, rLocale, rFontColor),
|
|
maOverlineColor(rOverlineColor),
|
|
maTextlineColor(rTextlineColor),
|
|
meFontOverline(eFontOverline),
|
|
meFontUnderline(eFontUnderline),
|
|
meTextStrikeout(eTextStrikeout),
|
|
meTextEmphasisMark(eTextEmphasisMark),
|
|
meTextRelief(eTextRelief),
|
|
mbUnderlineAbove(bUnderlineAbove),
|
|
mbWordLineMode(bWordLineMode),
|
|
mbEmphasisMarkAbove(bEmphasisMarkAbove),
|
|
mbEmphasisMarkBelow(bEmphasisMarkBelow),
|
|
mbShadow(bShadow)
|
|
{
|
|
}
|
|
|
|
bool TextDecoratedPortionPrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
|
|
{
|
|
if(TextSimplePortionPrimitive2D::operator==(rPrimitive))
|
|
{
|
|
const TextDecoratedPortionPrimitive2D& rCompare = (TextDecoratedPortionPrimitive2D&)rPrimitive;
|
|
|
|
return (getOverlineColor() == rCompare.getOverlineColor()
|
|
&& getTextlineColor() == rCompare.getTextlineColor()
|
|
&& getFontOverline() == rCompare.getFontOverline()
|
|
&& getFontUnderline() == rCompare.getFontUnderline()
|
|
&& getTextStrikeout() == rCompare.getTextStrikeout()
|
|
&& getTextEmphasisMark() == rCompare.getTextEmphasisMark()
|
|
&& getTextRelief() == rCompare.getTextRelief()
|
|
&& getUnderlineAbove() == rCompare.getUnderlineAbove()
|
|
&& getWordLineMode() == rCompare.getWordLineMode()
|
|
&& getEmphasisMarkAbove() == rCompare.getEmphasisMarkAbove()
|
|
&& getEmphasisMarkBelow() == rCompare.getEmphasisMarkBelow()
|
|
&& getShadow() == rCompare.getShadow());
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// #i96475#
|
|
// Added missing implementation. Decorations may (will) stick out of the text's
|
|
// inking area, so add them if needed
|
|
basegfx::B2DRange TextDecoratedPortionPrimitive2D::getB2DRange(const geometry::ViewInformation2D& rViewInformation) const
|
|
{
|
|
const bool bDecoratedIsNeeded(
|
|
TEXT_LINE_NONE != getFontOverline()
|
|
|| TEXT_LINE_NONE != getFontUnderline()
|
|
|| TEXT_STRIKEOUT_NONE != getTextStrikeout()
|
|
|| TEXT_EMPHASISMARK_NONE != getTextEmphasisMark()
|
|
|| TEXT_RELIEF_NONE != getTextRelief()
|
|
|| getShadow());
|
|
|
|
if(bDecoratedIsNeeded)
|
|
{
|
|
// decoration is used, fallback to BufferedDecompositionPrimitive2D::getB2DRange which uses
|
|
// the own local decomposition for computation and thus creates all necessary
|
|
// geometric objects
|
|
return BufferedDecompositionPrimitive2D::getB2DRange(rViewInformation);
|
|
}
|
|
else
|
|
{
|
|
// no relevant decoration used, fallback to TextSimplePortionPrimitive2D::getB2DRange
|
|
return TextSimplePortionPrimitive2D::getB2DRange(rViewInformation);
|
|
}
|
|
}
|
|
|
|
// provide unique ID
|
|
ImplPrimitrive2DIDBlock(TextDecoratedPortionPrimitive2D, PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D)
|
|
|
|
} // end of namespace primitive2d
|
|
} // end of namespace drawinglayer
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// eof
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|