39 stroke = parentIt->properties.stroke();
45 background = parentIt->properties.background();
60 painter.setRenderHint(QPainter::Antialiasing,
true);
61 painter.setRenderHint(QPainter::SmoothPixmapTransform,
true);
63 painter.setRenderHint(QPainter::Antialiasing,
false);
64 painter.setRenderHint(QPainter::SmoothPixmapTransform,
false);
68void KoSvgTextShape::Private::paintTextDecoration(QPainter &painter,
69 const QPainterPath &rootOutline,
86 stroke->strokeInsets(rootShape, insets);
88 QMap<KoSvgText::TextDecoration, QPainterPath> textDecorations = it->textDecorations;
90 if (textDecorations.isEmpty() || !textDecorations.contains(type))
continue;
92 const QPainterPath decorPath = textDecorations.value(type);
93 const QRect shapeGlobalClipRect = painter.transform().mapRect(decorPath.boundingRect().adjusted(-insets.
left, -insets.
top, insets.
right, insets.
bottom)).toAlignedRect();
95 if (!shapeGlobalClipRect.isValid())
continue;
97 const QRectF clipRect = painter.clipBoundingRect();
98 if (!clipRect.contains(decorPath.boundingRect()) &&
99 !clipRect.intersects(decorPath.boundingRect()))
continue;
108 setRenderHints(*fillPainter.maskPainter(), rendering, painter.testRenderHint(QPainter::Antialiasing));
109 background->paint(*fillPainter.shapePainter(), rootOutline);
110 fillPainter.maskPainter()->fillPath(rootOutline, Qt::black);
111 fillPainter.maskPainter()->fillPath(decorPath, Qt::white);
112 fillPainter.renderOnGlobalPainter();
113 }
else if (colorValid) {
114 painter.fillPath(decorPath, textDecorationColor);
121 if (strokeSP->lineBrush().gradient()) {
123 QPainterPath strokeOutline;
124 strokeOutline.addRect(rootOutline.boundingRect().adjusted(-insets.
left, -insets.
top, insets.
right, insets.
bottom));
125 strokePainter.shapePainter()->fillRect(strokeOutline.boundingRect(), strokeSP->lineBrush());
126 strokePainter.maskPainter()->fillRect(strokeOutline.boundingRect(), Qt::black);
129 maskStroke->setColor(Qt::white);
130 maskStroke->setLineBrush(Qt::white);
133 setRenderHints(*strokePainter.maskPainter(), rendering, painter.testRenderHint(QPainter::Antialiasing));
136 maskStroke->paint(shape.data(), *strokePainter.maskPainter());
138 strokePainter.renderOnGlobalPainter();
142 stroke->paint(shape.data(), painter);
154void KoSvgTextShape::Private::paintPaths(QPainter &painter,
155 const QPainterPath &rootOutline,
171 stroke->strokeInsets(rootShape, insets);
177 if (it->finalResultIndex < 0)
continue;
178 const int j = it->finalResultIndex;
180 const QRect shapeGlobalClipRect = painter.transform().mapRect(it->associatedOutline.boundingRect().adjusted(-insets.
left, -insets.
top, insets.
right, insets.
bottom)).toAlignedRect();
182 if (shapeGlobalClipRect.isValid()) {
185 background->paint(*fillPainter.shapePainter(), rootOutline);
186 fillPainter.maskPainter()->fillPath(rootOutline, Qt::black);
187 setRenderHints(*fillPainter.maskPainter(), rendering, painter.testRenderHint(QPainter::Antialiasing));
189 QPainterPath textDecorationsRest;
190 textDecorationsRest.setFillRule(Qt::WindingFill);
192 for (
int i = currentIndex; i < j; i++) {
193 if (result.at(i).addressable && !result.at(i).hidden) {
194 const QTransform tf = result.at(i).finalTransform();
201 const QRectF clipRect = painter.clipBoundingRect();
215 if (
const auto *colorGlyph = std::get_if<Glyph::ColorLayers>(&result.at(i).glyph)) {
216 for (
int c = 0; c < colorGlyph->paths.size(); c++) {
217 QBrush color = colorGlyph->colors.at(c);
218 bool replace = colorGlyph->replaceWithForeGroundColor.at(c);
226 painter.fillPath(tf.map(colorGlyph->paths.at(c)), color);
228 }
else if (
const auto *outlineGlyph = std::get_if<Glyph::Outline>(&result.at(i).glyph)) {
229 chunk.addPath(tf.map(outlineGlyph->path));
230 }
else if (
const auto *bitmapGlyph = std::get_if<Glyph::Bitmap>(&result.at(i).glyph)) {
231 for (
int b = 0;
b < bitmapGlyph->images.size();
b++) {
232 QImage img = bitmapGlyph->images.at(b);
233 QRectF
rect = bitmapGlyph->drawRects.value(b, QRectF(0, 0, img.width(), img.height()));
234 if (img.format() == QImage::Format_Grayscale8 || img.format() == QImage::Format_Mono) {
235 fillPainter.maskPainter()->save();
236 fillPainter.maskPainter()->translate(result.at(i).finalPosition.x(), result.at(i).finalPosition.y());
237 fillPainter.maskPainter()->rotate(qRadiansToDegrees(result.at(i).rotate));
238 fillPainter.maskPainter()->setCompositionMode(QPainter::CompositionMode_Plus);
239 fillPainter.maskPainter()->drawImage(
rect, img);
240 fillPainter.maskPainter()->restore();
243 painter.translate(result.at(i).finalPosition.x(), result.at(i).finalPosition.y());
244 painter.rotate(qRadiansToDegrees(result.at(i).rotate));
245 painter.setRenderHint(QPainter::SmoothPixmapTransform,
true);
246 painter.drawImage(
rect, img);
256 chunk.setFillRule(Qt::WindingFill);
257 fillPainter.maskPainter()->fillPath(chunk, Qt::white);
259 if (!textDecorationsRest.isEmpty()) {
260 fillPainter.maskPainter()->fillPath(textDecorationsRest.simplified(), Qt::white);
262 fillPainter.renderOnGlobalPainter();
269 if (strokeSP->lineBrush().gradient()) {
271 QPainterPath strokeOutline;
272 strokeOutline.addRect(rootOutline.boundingRect().adjusted(-insets.
left, -insets.
top, insets.
right, insets.
bottom));
273 strokePainter.shapePainter()->fillRect(strokeOutline.boundingRect(), strokeSP->lineBrush());
274 strokePainter.maskPainter()->fillRect(strokeOutline.boundingRect(), Qt::black);
276 maskStroke->setColor(Qt::white);
277 maskStroke->setLineBrush(Qt::white);
278 setRenderHints(*strokePainter.maskPainter(), rendering, painter.testRenderHint(QPainter::Antialiasing));
281 maskStroke->paint(shape.data(), *strokePainter.maskPainter());
283 if (!textDecorationsRest.isEmpty()) {
285 maskStroke->paint(shape.data(), *strokePainter.maskPainter());
287 strokePainter.renderOnGlobalPainter();
291 stroke->paint(shape.data(), painter);
293 if (!textDecorationsRest.isEmpty()) {
295 stroke->paint(shape.data(), painter);
303 chunk = QPainterPath();
313 if (newGrad->type() == QGradient::LinearGradient) {
314 QLinearGradient *lgradient =
static_cast<QLinearGradient*
>(newGrad);
315 lgradient->setStart(tf.map(lgradient->start()));
316 lgradient->setFinalStop(tf.map(lgradient->finalStop()));
317 }
else if (newGrad->type() == QGradient::RadialGradient) {
318 QRadialGradient *rgradient =
static_cast<QRadialGradient*
>(newGrad);
319 rgradient->setFocalPoint(tf.map(rgradient->focalPoint()));
320 rgradient->setCenter(tf.map(rgradient->center()));
330 QTransform newTf = QTransform::fromTranslate(relative.x(), relative.y());
331 newTf.scale(relative.width(), relative.height());
343 QBrush b =
s->lineBrush();
345 QRectF nb = newBounds;
348 s->strokeInsets(
nullptr, insets);
354 QTransform newTf = QTransform::fromTranslate(relative.x(), relative.y());
355 newTf.scale(relative.width(), relative.height());
357 newStroke->setLineBrush(newBrush);
371 if (!internalShapes().isEmpty()) {
374 Q_FOREACH(
KoShape *shape, internalS) {
380 shapes.append(clone);
385 const QString imageProp =
"image";
386 const QString imageViewTransformProp =
"viewboxTransform";
393 bool currentNodeInheritsBg =
false;
394 bool currentNodeInheritsStroke =
false;
399 QMap<KoSvgText::TextDecoration, QPainterPath> textDecorations = it->textDecorations;
407 stroke->strokeInsets(rootShape, insets);
431 shapes.append(shape);
432 if (currentNodeInheritsBg && !textDecorationColor.isValid()) {
449 shapes.append(shape);
450 if (currentNodeInheritsBg && !textDecorationColor.isValid()) {
459 const int j = it->finalResultIndex;
460 if (j < 0 || j > result.size())
continue;
461 for (
int i = currentIndex; i < j; i++) {
462 if (result.at(i).addressable && !result.at(i).hidden) {
463 const QTransform tf = result.at(i).finalTransform();
464 if (
const auto *colorGlyph = std::get_if<Glyph::ColorLayers>(&result.at(i).glyph)) {
465 for (
int c = 0; c < colorGlyph->paths.size(); c++) {
466 QBrush color = colorGlyph->colors.at(c);
467 bool replace = colorGlyph->replaceWithForeGroundColor.at(c);
480 shapes.append(shape);
481 if (replace && currentNodeInheritsBg) {
486 }
else if (
const auto *outlineGlyph = std::get_if<Glyph::Outline>(&result.at(i).glyph)) {
487 chunk.addPath(tf.map(outlineGlyph->path));
488 }
else if (
const auto *bitmapGlyph = std::get_if<Glyph::Bitmap>(&result.at(i).glyph)) {
490 for (
int b = 0;
b < bitmapGlyph->images.size();
b++) {
491 QImage img = bitmapGlyph->images.at(b);
492 QRectF drawRect = bitmapGlyph->drawRects.at(b);
494 QTransform imageTf = QTransform::fromTranslate(drawRect.x(), drawRect.y());
495 QTransform viewBox = QTransform::fromScale(drawRect.width()/img.width(),
496 drawRect.height()/img.height());
498 params.
setProperty(imageViewTransformProp, viewBox);
500 if (img.format() == QImage::Format_Grayscale8 || img.format() == QImage::Format_Mono) {
502 shape->
setSize(drawRect.size());
503 rect->setSize(drawRect.size());
504 rect->setStroke(
nullptr);
507 rect->setClipMask(mask);
508 rect->setZIndex(shapes.size());
511 tf.mapRect(drawRect)));
512 rect->setTransformation(imageTf*tf);
515 rect->setInheritBackground(currentNodeInheritsBg);
516 rect->setInheritStroke(currentNodeInheritsStroke);
518 shape->
setSize(drawRect.size());
521 shapes.append(shape);
539 shapes.append(shape);
549 currentNodeInheritsBg =
true;
550 currentNodeInheritsStroke =
true;
567 shapes.append(shape);
568 if (currentNodeInheritsBg && !textDecorationColor.isValid()) {
577 if (shapes.size() == 1) {
578 parentShape = shapes.first();
579 }
else if (shapes.size() > 1) {
599void KoSvgTextShape::Private::paintDebug(QPainter &painter,
604 for (
auto it = textData.depthFirstTailBegin(); it != textData.depthFirstTailEnd(); it++) {
605 const int j = it->finalResultIndex;
606 if (currentIndex > result.size())
continue;
607 if (j < 0 || j > result.size())
continue;
609 const QRect shapeGlobalClipRect = painter.transform().mapRect(it->associatedOutline.boundingRect()).toAlignedRect();
613 QFont font(QFont(), painter.device());
614 font.setPointSizeF(16.0);
616 if (shapeGlobalClipRect.isValid() && childCount(
siblingCurrent(it)) == 0) {
617 for (
int i = currentIndex; i < j; i++) {
618 if (result.at(i).addressable && !result.at(i).hidden) {
619 const QTransform tf = result.at(i).finalTransform();
622 painter.setBrush(Qt::transparent);
623 QPen pen(QColor(0, 0, 0, 50));
624 pen.setCosmetic(
true);
627 if (
const auto *bitmapGlyph = std::get_if<Glyph::Bitmap>(&result.at(i).glyph)) {
628 Q_FOREACH(
const QRectF drawRect, bitmapGlyph->drawRects) {
629 painter.drawPolygon(tf.map(drawRect));
631 }
else if (
const auto *colorGlyph = std::get_if<Glyph::ColorLayers>(&result.at(i).glyph)) {
633 Q_FOREACH (
const QPainterPath &
p, colorGlyph->paths) {
637 }
else if (
const auto *outlineGlyph = std::get_if<Glyph::Outline>(&result.at(i).glyph)) {
638 painter.drawPolygon(tf.map(outlineGlyph->path.boundingRect()));
640 QColor penColor = result.at(i).anchored_chunk ? result.at(i).isHanging ? Qt::red : Qt::magenta
643 penColor.setAlpha(192);
644 pen.setColor(penColor);
646 painter.drawPolygon(tf.map(result.at(i).layoutBox()));
648 penColor.setAlpha(96);
649 pen.setColor(penColor);
651 pen.setStyle(Qt::DotLine);
653 painter.drawPolygon(tf.map(result.at(i).lineHeightBox()));
655 pen.setStyle(Qt::SolidLine);
658 penColor.setAlpha(192);
659 pen.setColor(penColor);
661 painter.drawLine(tf.map(result.at(i).cursorInfo.caret));
664 const QPointF center = tf.mapRect(result.at(i).layoutBox()).center();
666 text += QString::number(i);
670 while (end < result.size() && result[end].middle) {
676 text += QString::number(end);
679 text += QString(
"\n(%1)").arg(result.at(i).plaintTextIndex);
680 painter.setWorldMatrixEnabled(
false);
681 painter.setPen(Qt::red);
682 painter.drawText(QRectF(painter.transform().map(center), QSizeF(0, 64)).adjusted(-128, 0, 128, 0),
683 Qt::AlignHCenter | Qt::AlignTop,
685 painter.setWorldMatrixEnabled(
true);
688 const BreakType breakType = result.at(i).breakType;
695 penColor.setAlpha(128);
696 pen.setColor(penColor);
698 painter.drawPoint(center);
701 penColor = Qt::darkGreen;
702 penColor.setAlpha(192);
703 pen.setColor(penColor);
706 for (
int k=0; k<offset.size(); k++) {
707 painter.drawPoint(tf.map(offset.at(k)));
711 penColor.setAlpha(192);
712 pen.setColor(penColor);
714 painter.drawPoint(result.at(i).finalPosition);
QSharedPointer< KoShapeStroke > KoShapeStrokeSP
@ NoChange
Do nothing special.
static void inheritPaintProperties(const KisForest< KoSvgTextContentElement >::composition_iterator it, KoShapeStrokeModelSP &stroke, QSharedPointer< KoShapeBackground > &background, QVector< KoShape::PaintOrder > &paintOrder)
QGradient * cloneAndTransformGradient(const QGradient *grad, const QTransform &tf)
KoShapeStrokeModelSP transformStrokeBgToNewBounds(KoShapeStrokeModelSP stroke, const QRectF &oldBounds, const QRectF &newBounds, bool calcInsets=true)
QSharedPointer< KoShapeBackground > transformBackgroundToBounds(QSharedPointer< KoShapeBackground > bg, const QRectF &oldBounds, const QRectF &newBounds)
void setRenderHints(QPainter &painter, const KoSvgText::TextRendering textRendering, const bool testAntialiasing)
A simple solid color shape background.
const T value(const QString &id) const
A gradient shape background.
const QGradient * gradient() const
Returns the gradient.
QTransform transform() const
Returns the transform matrix.
The position of a path point within a path shape.
QRectF outlineRect() const override
reimplemented
void setFillRule(Qt::FillRule fillRule)
Sets the fill rule to be used for painting the background.
static KoPathShape * createShapeFromPainterPath(const QPainterPath &path)
Creates path shape from given QPainterPath.
void setProperty(const QString &name, const QVariant &value)
virtual KoShape * createDefaultShape(KoDocumentResourceManager *documentResources=0) const
virtual KoShape * createShape(const KoProperties *params, KoDocumentResourceManager *documentResources=0) const
The undo / redo command for grouping shapes.
static KoShapeRegistry * instance()
virtual void setPaintOrder(PaintOrder first, PaintOrder second)
setPaintOrder set the paint order. As there's only three entries in any given paintorder,...
void setName(const QString &name)
virtual QRectF outlineRect() const
void setInheritBackground(bool value)
setInheritBackground marks a shape as inheriting the background from the parent shape....
void setZIndex(qint16 zIndex)
virtual QVector< PaintOrder > paintOrder() const
paintOrder
virtual KoShapeStrokeModelSP stroke() const
static bool compareShapeZIndex(KoShape *s1, KoShape *s2)
virtual QRectF boundingRect() const
Get the bounding box of the shape.
virtual void setStroke(KoShapeStrokeModelSP stroke)
QTransform absoluteTransformation() const
void setTransformation(const QTransform &matrix)
virtual void setBackground(QSharedPointer< KoShapeBackground > background)
virtual KoShape * cloneShape() const
creates a deep copy of the shape or shape's subtree
virtual QSharedPointer< KoShapeBackground > background() const
bool inheritPaintOrder() const
inheritPaintOrder
void setInheritStroke(bool value)
setInheritStroke marks a shape as inheriting the stroke from the parent shape. NOTE: The currently se...
QSharedDataPointer< SharedData > s
void setInheritPaintOrder(bool value)
setInheritPaintOrder set inherit paint order.
virtual void setSize(const QSizeF &size)
Resize the shape.
@ PaintOrder
QVector<KoShape::PaintOrder>
@ TextDecorationColorId
QColor.
@ StrokeId
KoSvgText::StrokeProperty.
@ FillId
KoSvgText::BackgroundProperty.
QAction * replace(const QObject *recvr, const char *slot, QObject *parent)
QPointF absoluteToRelative(const QPointF &pt, const QRectF &rc)
ResultIterator hierarchyBegin(Iterator it)
ResultIterator hierarchyEnd(Iterator it)
ChildIterator< value_type, is_const > siblingCurrent(ChildIterator< value_type, is_const > it)
ResultIterator compositionEnd(Iterator it)
ResultIterator compositionBegin(Iterator it)
KRITAFLAKE_EXPORT QGradient * cloneGradient(const QGradient *gradient)
clones the given gradient
TextDecoration
Flags for text-decoration, for underline, overline and strikethrough.
void setShapes(const QList< KoShape * > &value)
qreal bottom
Bottom inset.