summaryrefslogtreecommitdiff
path: root/drawinglayer/source/primitive2d
diff options
context:
space:
mode:
Diffstat (limited to 'drawinglayer/source/primitive2d')
-rw-r--r--drawinglayer/source/primitive2d/Tools.cxx2
-rw-r--r--drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx117
-rw-r--r--drawinglayer/source/primitive2d/texthierarchyprimitive2d.cxx12
-rw-r--r--drawinglayer/source/primitive2d/textlayoutdevice.cxx45
-rw-r--r--drawinglayer/source/primitive2d/textprimitive2d.cxx51
5 files changed, 209 insertions, 18 deletions
diff --git a/drawinglayer/source/primitive2d/Tools.cxx b/drawinglayer/source/primitive2d/Tools.cxx
index 52545212b8cc..e1c3dfe96e80 100644
--- a/drawinglayer/source/primitive2d/Tools.cxx
+++ b/drawinglayer/source/primitive2d/Tools.cxx
@@ -241,6 +241,8 @@ OUString idToString(sal_uInt32 nId)
return u"BITMAPALPHAPRIMITIVE2D"_ustr;
case PRIMITIVE2D_ID_POLYPOLYGONALPHAGRADIENTPRIMITIVE2D:
return u"POLYPOLYGONALPHAGRADIENTPRIMITIVE2D"_ustr;
+ case PRIMITIVE2D_ID_TEXTHIERARCHYEMPHASISMARKPRIMITIVE2D:
+ return u"TEXTHIERARCHYEMPHASISMARKPRIMITIVE2D"_ustr;
default:
return OUString::number((nId >> 16) & 0xFF) + "|" + OUString::number(nId & 0xFF);
}
diff --git a/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx b/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx
index 41a09c5968ea..d500e4476785 100644
--- a/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/textdecoratedprimitive2d.cxx
@@ -22,10 +22,14 @@
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <primitive2d/texteffectprimitive2d.hxx>
#include <drawinglayer/primitive2d/shadowprimitive2d.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonHairlinePrimitive2D.hxx>
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
#include <primitive2d/textlineprimitive2d.hxx>
#include <primitive2d/textstrikeoutprimitive2d.hxx>
#include <drawinglayer/primitive2d/textbreakuphelper.hxx>
-
+#include <vcl/vcllayout.hxx>
namespace drawinglayer::primitive2d
{
@@ -75,8 +79,10 @@ namespace drawinglayer::primitive2d
const bool bOverlineUsed(TEXT_LINE_NONE != getFontOverline());
const bool bUnderlineUsed(TEXT_LINE_NONE != getFontUnderline());
const bool bStrikeoutUsed(TEXT_STRIKEOUT_NONE != getTextStrikeout());
+ const bool bEmphasisMarkUsed(TEXT_FONT_EMPHASIS_MARK_NONE != getTextEmphasisMark()
+ && (getEmphasisMarkAbove() || getEmphasisMarkBelow()));
- if(!(bUnderlineUsed || bStrikeoutUsed || bOverlineUsed))
+ if(!(bUnderlineUsed || bStrikeoutUsed || bOverlineUsed || bEmphasisMarkUsed))
{
// not used, return empty Primitive2DContainer
return maBufferedDecorationGeometry;
@@ -88,16 +94,9 @@ namespace drawinglayer::primitive2d
return maBufferedDecorationGeometry;
}
- // 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());
+ // common preparations - create TextLayouterDevice
+ primitive2d::TextLayouterDevice aTextLayouter;
+ createTextLayouter(aTextLayouter);
// get text width
double fTextWidth(0.0);
@@ -176,7 +175,99 @@ namespace drawinglayer::primitive2d
}
}
- // TODO: Handle Font Emphasis Above/Below
+ if (bEmphasisMarkUsed)
+ {
+ // create primitives for EmphasisMark visualization - we need a SalLayout
+ std::unique_ptr<SalLayout> pSalLayout(createSalLayout(aTextLayouter));
+
+ if (pSalLayout)
+ {
+ // placeholders for repeated content, only created once
+ Primitive2DReference aShape;
+ Primitive2DReference aRect1;
+ Primitive2DReference aRect2;
+
+ // space to collect primitives for EmphasisMark
+ Primitive2DContainer aEmphasisContent;
+
+ // callback collector will produce geometry alraeyd scaled, so
+ // prepare local transform without FontScale
+ const basegfx::B2DHomMatrix aObjTransformWithoutScale(
+ basegfx::utils::createShearXRotateTranslateB2DHomMatrix(
+ rDecTrans.getShearX(), rDecTrans.getRotate(), rDecTrans.getTranslate()));
+
+ // the callback from OutputDevice::createEmphasisMarks providing the data
+ // for each EmphasisMark
+ auto aEmphasisCallback([this, &aShape, &aRect1, &aRect2, &aEmphasisContent, &aObjTransformWithoutScale](
+ const basegfx::B2DPoint& rOutPoint, const basegfx::B2DPolyPolygon& rShape,
+ bool isPolyLine, const tools::Rectangle& rRect1, const tools::Rectangle& rRect2)
+ {
+ // prepare complete ObjectTransform
+ const basegfx::B2DHomMatrix aTransform(
+ aObjTransformWithoutScale * basegfx::utils::createTranslateB2DHomMatrix(rOutPoint));
+
+ if (rShape.count())
+ {
+ // create PolyPolygon if provided
+ if (!aShape)
+ {
+ if (isPolyLine)
+ aShape = new PolyPolygonHairlinePrimitive2D(rShape, getFontColor());
+ else
+ aShape = new PolyPolygonColorPrimitive2D(rShape, getFontColor());
+ }
+
+ aEmphasisContent.push_back(
+ new TransformPrimitive2D(
+ aTransform,
+ Primitive2DContainer { aShape } ));
+ }
+
+ if (!rRect1.IsEmpty())
+ {
+ // create Rectangle1 if provided
+ if (!aRect1)
+ aRect1 = new FilledRectanglePrimitive2D(
+ basegfx::B2DRange(rRect1.Left(), rRect1.Top(), rRect1.Right(), rRect1.Bottom()), getFontColor());
+
+ aEmphasisContent.push_back(
+ new TransformPrimitive2D(
+ aTransform,
+ Primitive2DContainer { aRect1 } ));
+ }
+
+ if (!rRect2.IsEmpty())
+ {
+ // create Rectangle2 if provided
+ if (!aRect2)
+ aRect2 = new FilledRectanglePrimitive2D(
+ basegfx::B2DRange(rRect2.Left(), rRect2.Top(), rRect2.Right(), rRect2.Bottom()), getFontColor());
+
+ aEmphasisContent.push_back(
+ new TransformPrimitive2D(
+ aTransform,
+ Primitive2DContainer { aRect2 } ));
+ }
+ });
+
+ // call tooling method in vcl to generate the graphic representations
+ aTextLayouter.createEmphasisMarks(
+ *pSalLayout,
+ getTextEmphasisMark(),
+ getEmphasisMarkAbove(),
+ aEmphasisCallback);
+
+ if (!aEmphasisContent.empty())
+ {
+ // if we got graphic representations of EmphasisMark, add
+ // them to BufferedDecorationGeometry. Also embed them to
+ // a TextHierarchyEmphasisMarkPrimitive2D GroupPrimitive
+ // to be able to evtl. handle these in a special way
+ maBufferedDecorationGeometry.push_back(
+ new TextHierarchyEmphasisMarkPrimitive2D(std::move(aEmphasisContent)));
+ }
+ }
+ }
// append local result and return
return maBufferedDecorationGeometry;
diff --git a/drawinglayer/source/primitive2d/texthierarchyprimitive2d.cxx b/drawinglayer/source/primitive2d/texthierarchyprimitive2d.cxx
index 655918904cfb..73a21e3c5722 100644
--- a/drawinglayer/source/primitive2d/texthierarchyprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/texthierarchyprimitive2d.cxx
@@ -156,6 +156,18 @@ namespace drawinglayer::primitive2d
return PRIMITIVE2D_ID_TEXTHIERARCHYEDITPRIMITIVE2D;
}
+
+ TextHierarchyEmphasisMarkPrimitive2D::TextHierarchyEmphasisMarkPrimitive2D(Primitive2DContainer&& aContent)
+ : GroupPrimitive2D(std::move(aContent))
+ {
+ }
+
+ // provide unique ID
+ sal_uInt32 TextHierarchyEmphasisMarkPrimitive2D::getPrimitive2DID() const
+ {
+ return PRIMITIVE2D_ID_TEXTHIERARCHYEMPHASISMARKPRIMITIVE2D;
+ }
+
} // end of namespace
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/primitive2d/textlayoutdevice.cxx b/drawinglayer/source/primitive2d/textlayoutdevice.cxx
index 3a6667d0461f..51c75f433ad6 100644
--- a/drawinglayer/source/primitive2d/textlayoutdevice.cxx
+++ b/drawinglayer/source/primitive2d/textlayoutdevice.cxx
@@ -365,11 +365,10 @@ std::vector<double> TextLayouterDevice::getTextArray(const OUString& rText, sal_
return aRetval;
}
-std::unique_ptr<SalLayout> TextLayouterDevice::getSalLayout(const OUString& rText,
- sal_uInt32 nIndex, sal_uInt32 nLength,
- const basegfx::B2DPoint& rStartPoint,
- const KernArray& rDXArray,
- std::span<const sal_Bool> pKashidaAry)
+std::unique_ptr<SalLayout>
+TextLayouterDevice::getSalLayout(const OUString& rText, sal_uInt32 nIndex, sal_uInt32 nLength,
+ const basegfx::B2DPoint& rStartPoint, const KernArray& rDXArray,
+ std::span<const sal_Bool> pKashidaAry) const
{
const SalLayoutGlyphs* pGlyphs(
SalLayoutGlyphsCache::self()->GetLayoutGlyphs(&mrDevice, rText, nIndex, nLength));
@@ -380,6 +379,42 @@ std::unique_ptr<SalLayout> TextLayouterDevice::getSalLayout(const OUString& rTex
SalLayoutFlags::NONE, nullptr, pGlyphs);
}
+void TextLayouterDevice::createEmphasisMarks(
+ SalLayout& rSalLayout, TextEmphasisMark aTextEmphasisMark, bool bAbove,
+ std::function<void(const basegfx::B2DPoint&, const basegfx::B2DPolyPolygon&, bool,
+ const tools::Rectangle&, const tools::Rectangle&)>
+ aCallback) const
+{
+ FontEmphasisMark nEmphasisMark(FontEmphasisMark::NONE);
+ double fEmphasisHeight(getTextHeight() * (250.0 / 1000.0));
+
+ switch (aTextEmphasisMark)
+ {
+ case TEXT_FONT_EMPHASIS_MARK_DOT:
+ nEmphasisMark = FontEmphasisMark::Dot;
+ break;
+ case TEXT_FONT_EMPHASIS_MARK_CIRCLE:
+ nEmphasisMark = FontEmphasisMark::Circle;
+ break;
+ case TEXT_FONT_EMPHASIS_MARK_DISC:
+ nEmphasisMark = FontEmphasisMark::Disc;
+ break;
+ case TEXT_FONT_EMPHASIS_MARK_ACCENT:
+ nEmphasisMark = FontEmphasisMark::Accent;
+ break;
+ default:
+ break;
+ }
+
+ if (bAbove)
+ nEmphasisMark |= FontEmphasisMark::PosAbove;
+ else
+ nEmphasisMark |= FontEmphasisMark::PosBelow;
+
+ mrDevice.createEmphasisMarks(nEmphasisMark, static_cast<tools::Long>(fEmphasisHeight),
+ rSalLayout, aCallback);
+}
+
// helper methods for vcl font handling
vcl::Font getVclFontFromFontAttribute(const attribute::FontAttribute& rFontAttribute,
diff --git a/drawinglayer/source/primitive2d/textprimitive2d.cxx b/drawinglayer/source/primitive2d/textprimitive2d.cxx
index 820b3d39f804..ec2d18a79204 100644
--- a/drawinglayer/source/primitive2d/textprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/textprimitive2d.cxx
@@ -25,6 +25,9 @@
#include <drawinglayer/primitive2d/groupprimitive2d.hxx>
#include <primitive2d/texteffectprimitive2d.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <vcl/vcllayout.hxx>
+#include <vcl/rendercontext/State.hxx>
+#include <vcl/kernarray.hxx>
#include <utility>
#include <osl/diagnose.h>
@@ -296,6 +299,54 @@ basegfx::B2DRange TextSimplePortionPrimitive2D::getB2DRange(
return maB2DRange;
}
+void TextSimplePortionPrimitive2D::createTextLayouter(TextLayouterDevice& rTextLayouter) const
+{
+ // decompose primitive-local matrix to get local font scaling
+ const basegfx::utils::B2DHomMatrixBufferedOnDemandDecompose aDecTrans(getTextTransform());
+
+ // create a TextLayouter to access encapsulated VCL Text/Font related tooling
+ rTextLayouter.setFontAttribute(getFontAttribute(), aDecTrans.getScale().getX(),
+ aDecTrans.getScale().getY(), getLocale());
+
+ if (getFontAttribute().getRTL())
+ {
+ vcl::text::ComplexTextLayoutFlags nRTLLayoutMode(
+ rTextLayouter.getLayoutMode() & ~vcl::text::ComplexTextLayoutFlags::BiDiStrong);
+ nRTLLayoutMode |= vcl::text::ComplexTextLayoutFlags::BiDiRtl
+ | vcl::text::ComplexTextLayoutFlags::TextOriginLeft;
+ rTextLayouter.setLayoutMode(nRTLLayoutMode);
+ }
+ else
+ {
+ // tdf#101686: This is LTR text, but the output device may have RTL state.
+ vcl::text::ComplexTextLayoutFlags nLTRLayoutMode(rTextLayouter.getLayoutMode());
+ nLTRLayoutMode = nLTRLayoutMode & ~vcl::text::ComplexTextLayoutFlags::BiDiRtl;
+ nLTRLayoutMode = nLTRLayoutMode & ~vcl::text::ComplexTextLayoutFlags::BiDiStrong;
+ rTextLayouter.setLayoutMode(nLTRLayoutMode);
+ }
+}
+
+std::unique_ptr<SalLayout>
+TextSimplePortionPrimitive2D::createSalLayout(TextLayouterDevice& rTextLayouter) const
+{
+ // create integer DXArray. As mentioned above we can act in the
+ // Text's local coordinate system without transformation at all
+ const ::std::vector<double>& rDXArray(getDXArray());
+ KernArray aDXArray;
+
+ if (!rDXArray.empty())
+ {
+ aDXArray.reserve(rDXArray.size());
+ for (auto const& elem : rDXArray)
+ aDXArray.push_back(basegfx::fround(elem));
+ }
+
+ // create SalLayout. No need for a position, as mentioned text can work
+ // without transformations, so start point is always 0,0
+ return rTextLayouter.getSalLayout(getText(), getTextPosition(), getTextLength(),
+ basegfx::B2DPoint(0.0, 0.0), aDXArray, getKashidaArray());
+}
+
// provide unique ID
sal_uInt32 TextSimplePortionPrimitive2D::getPrimitive2DID() const
{