/* -*- 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 .
*/
// anonymous helpers namespace
{
rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D>
CheckFieldPrimitive(drawinglayer::primitive2d::BasePrimitive2D* pPrimitive, const DrawPortionInfo& rInfo)
{
rtl::Reference<drawinglayer::primitive2d::BasePrimitive2D> xRet = pPrimitive; if (rInfo.mpFieldData)
{ // Support for FIELD_SEQ_BEGIN, FIELD_SEQ_END. If used, create a TextHierarchyFieldPrimitive2D // which holds the field type and, if applicable, the URL const SvxURLField* pURLField = dynamic_cast<const SvxURLField*>(rInfo.mpFieldData); const SvxPageField* pPageField = dynamic_cast<const SvxPageField*>(rInfo.mpFieldData);
// embed current primitive to a sequence
drawinglayer::primitive2d::Primitive2DContainer aSequence;
if (pPrimitive)
{
aSequence.resize(1);
aSequence[0] = drawinglayer::primitive2d::Primitive2DReference(pPrimitive);
}
if (pURLField)
{ // extended this to hold more of the contents of the original // SvxURLField since that stuff is still used in HitTest and e.g. Calc
std::vector<std::pair<OUString, OUString>> meValues;
meValues.emplace_back("URL", pURLField->GetURL());
meValues.emplace_back("Representation", pURLField->GetRepresentation());
meValues.emplace_back("TargetFrame", pURLField->GetTargetFrame());
meValues.emplace_back("AltText", pURLField->GetName());
meValues.emplace_back( "SvxURLFormat", OUString::number(static_cast<sal_uInt16>(pURLField->GetFormat())));
xRet = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(
std::move(aSequence), drawinglayer::primitive2d::FIELD_TYPE_URL, &meValues);
} elseif (pPageField)
{
xRet = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(
std::move(aSequence), drawinglayer::primitive2d::FIELD_TYPE_PAGE);
} else
{
xRet = new drawinglayer::primitive2d::TextHierarchyFieldPrimitive2D(
std::move(aSequence), drawinglayer::primitive2d::FIELD_TYPE_COMMON);
}
}
return xRet;
}
class DoCapitalsDrawPortionInfo : public SvxDoCapitals
{ private:
drawinglayer::primitive2d::Primitive2DContainer& mrTarget; const basegfx::B2DHomMatrix& mrNewTransformA; const basegfx::B2DHomMatrix& mrNewTransformB; const DrawPortionInfo& m_rInfo;
SvxFont m_aFont;
/* turn all these off as they are handled outside subportions for the whole portion */
m_aFont.SetTransparent(false);
m_aFont.SetUnderline(LINESTYLE_NONE);
m_aFont.SetOverline(LINESTYLE_NONE);
m_aFont.SetStrikeout(STRIKEOUT_NONE);
if (!rInfo.mpKashidaArray.empty() && rInfo.mnTextLen)
{
aKashidaArray.reserve(rInfo.mnTextLen);
for (sal_Int32 a = 0; a < rInfo.mnTextLen; a++)
{
aKashidaArray.push_back(rInfo.mpKashidaArray[a]);
}
}
// create complex text primitive and append const Color aFontColor(rInfo.mrFont.GetColor()); const basegfx::BColor aBFontColor(aFontColor.getBColor());
const Color aTextFillColor(rInfo.mrFont.GetFillColor());
// prepare wordLineMode (for underline and strikeout) // NOT for bullet texts. It is set (this may be an error by itself), but needs to be suppressed to hinder e.g. '1)' // to be split which would not look like the original constbool bWordLineMode(rInfo.mrFont.IsWordLineMode() && !rInfo.mbEndOfBullet);
if (bDecoratedIsNeeded)
{ // TextDecoratedPortionPrimitive2D needed, prepare some more data // get overline and underline color. If it's on automatic (0xffffffff) use FontColor instead const Color aUnderlineColor(rInfo.maTextLineColor); const basegfx::BColor aBUnderlineColor(
(aUnderlineColor == COL_AUTO) ? aBFontColor : aUnderlineColor.getBColor()); const Color aOverlineColor(rInfo.maOverlineColor); const basegfx::BColor aBOverlineColor(
(aOverlineColor == COL_AUTO) ? aBFontColor : aOverlineColor.getBColor());
// prepare overline and underline data const drawinglayer::primitive2d::TextLine eFontOverline(
drawinglayer::primitive2d::mapFontLineStyleToTextLine(rInfo.mrFont.GetOverline())); const drawinglayer::primitive2d::TextLine eFontLineStyle(
drawinglayer::primitive2d::mapFontLineStyleToTextLine(rInfo.mrFont.GetUnderline()));
// add font scale to new transform
aNewTransform.scale(aFontScaling.getX(), aFontScaling.getY());
// look for proportional font scaling, if necessary, scale accordingly
sal_Int8 nPropr(rInfo.mrFont.GetPropr()); constdouble fPropFontFactor(nPropr / 100.0); if (100 != nPropr)
aNewTransform.scale(fPropFontFactor, fPropFontFactor);
// apply font rotate if (rInfo.mrFont.GetOrientation())
{
aNewTransform.rotate(-toRadians(rInfo.mrFont.GetOrientation()));
}
// look for escapement, if necessary, translate accordingly if (rInfo.mrFont.GetEscapement())
{
sal_Int16 nEsc(rInfo.mrFont.GetEscapement());
if (DFLT_ESC_AUTO_SUPER == nEsc)
{
nEsc = .8 * (100 - nPropr);
assert(nEsc == DFLT_ESC_SUPER
&& "I'm sure this formula needs to be changed, but how to confirm that???");
nEsc = DFLT_ESC_SUPER;
} elseif (DFLT_ESC_AUTO_SUB == nEsc)
{
nEsc = .2 * -(100 - nPropr);
assert(nEsc == -20
&& "I'm sure this formula needs to be changed, but how to confirm that???");
nEsc = -20;
}
// apply local offset
aNewTransform.translate(rInfo.mrStartPos.X(), rInfo.mrStartPos.Y());
// also apply embedding object's transform
aNewTransform *= rNewTransformB;
// prepare DXArray content. To make it independent from font size (and such from // the text transformation), scale it to unit coordinates
::std::vector<double> aDXArray;
if (!rInfo.mpDXArray.empty())
{
aDXArray.reserve(rInfo.mnTextLen); for (sal_Int32 a = 0; a < rInfo.mnTextLen; a++)
{
aDXArray.push_back(rInfo.mpDXArray[a]);
}
}
bool bSmallCaps = rInfo.mrFont.IsCapital(); if (bSmallCaps && rInfo.mpDXArray.empty())
{
SAL_WARN("svx", "SmallCaps requested with DXArray, abandoning");
bSmallCaps = false;
} if (bSmallCaps)
{ // rerun with each sub-portion
DoCapitalsDrawPortionInfo aDoDrawPortionInfo(rTarget, rNewTransformA, rNewTransformB,
rInfo);
rInfo.mrFont.DoOnCapitals(aDoDrawPortionInfo);
// transfer collected primitives from rTarget to a new container
drawinglayer::primitive2d::Primitive2DContainer aContainer = std::move(rTarget);
// Take any decoration for the whole formatted portion and keep it to get continuous over/under/strike-through if (pNewPrimitive->getPrimitive2DID() == PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D)
{ const drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D* pTCPP
= static_cast<const drawinglayer::primitive2d::TextDecoratedPortionPrimitive2D*>(
pNewPrimitive.get());
if (pTCPP->getWordLineMode()) // single word mode: 'Individual words' in UI
{ // Split to single word primitives using TextBreakupHelper
drawinglayer::primitive2d::TextBreakupHelper aTextBreakupHelper(*pTCPP);
drawinglayer::primitive2d::Primitive2DContainer aBroken(
aTextBreakupHelper.extractResult(drawinglayer::primitive2d::BreakupUnit::Word)); for (auto& rPortion : aBroken)
{
assert(rPortion->getPrimitive2DID()
== PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D
&& "TextBreakupHelper generates same output primitive type as input");
pNewPrimitive = new drawinglayer::primitive2d::GroupPrimitive2D(std::move(aContainer));
}
const Color aFontColor(rInfo.mrFont.GetColor()); if (aFontColor.IsTransparent())
{ // Handle semi-transparent text for both the decorated and simple case here.
pNewPrimitive = new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(
drawinglayer::primitive2d::Primitive2DContainer{ pNewPrimitive },
(255 - aFontColor.GetAlpha()) / 255.0);
}
if (rInfo.mbEndOfBullet)
{ // embed in TextHierarchyBulletPrimitive2D
drawinglayer::primitive2d::Primitive2DContainer aNewSequence{ pNewPrimitive };
pNewPrimitive = new drawinglayer::primitive2d::TextHierarchyBulletPrimitive2D(
std::move(aNewSequence));
}
if (rInfo.mpFieldData)
{
pNewPrimitive = CheckFieldPrimitive(pNewPrimitive.get(), rInfo);
}
rTarget.push_back(pNewPrimitive);
// support for WrongSpellVector. Create WrongSpellPrimitives as needed if (!rInfo.mpWrongSpellVector || aDXArray.empty()) return;
if (!basegfx::fTools::equal(fStart, fEnd))
{ if (rInfo.IsRTL())
{ // #i98523# // When the portion is RTL, mirror the redlining using the // full portion width constdouble fTextWidth(aDXArray[aDXArray.size() - 1]);
// need to take FontScaling out of values; it's already part of // aNewTransform and would be double applied constdouble fFontScaleX(aFontScaling.getX() * fPropFontFactor);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.