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;
346 QRectF ob = oldBounds;
349 s->strokeInsets(
nullptr, insets);
356 QTransform newTf = QTransform::fromTranslate(relative.x(), relative.y());
357 newTf.scale(relative.width(), relative.height());
359 newStroke->setLineBrush(newBrush);
373 if (!internalShapes().isEmpty()) {
376 Q_FOREACH(
KoShape *shape, internalS) {
382 shapes.append(clone);
387 const QString imageProp =
"image";
388 const QString imageViewTransformProp =
"viewboxTransform";
395 const QRectF rootOutline = Private::boundingBoxFromTree(textData, rootShape,
false);
397 bool currentNodeInheritsBg =
false;
398 bool currentNodeInheritsStroke =
false;
403 QMap<KoSvgText::TextDecoration, QPainterPath> textDecorations = it->textDecorations;
411 stroke->strokeInsets(rootShape, insets);
435 shapes.append(shape);
436 if (currentNodeInheritsBg && !textDecorationColor.isValid()) {
453 shapes.append(shape);
454 if (currentNodeInheritsBg && !textDecorationColor.isValid()) {
463 const int j = it->finalResultIndex;
464 if (j < 0 || j > result.size())
continue;
465 for (
int i = currentIndex; i < j; i++) {
466 if (result.at(i).addressable && !result.at(i).hidden) {
467 const QTransform tf = result.at(i).finalTransform();
468 if (
const auto *colorGlyph = std::get_if<Glyph::ColorLayers>(&result.at(i).glyph)) {
469 for (
int c = 0; c < colorGlyph->paths.size(); c++) {
470 QBrush color = colorGlyph->colors.at(c);
471 bool replace = colorGlyph->replaceWithForeGroundColor.at(c);
484 shapes.append(shape);
485 if (replace && currentNodeInheritsBg) {
490 }
else if (
const auto *outlineGlyph = std::get_if<Glyph::Outline>(&result.at(i).glyph)) {
491 chunk.addPath(tf.map(outlineGlyph->path));
492 }
else if (
const auto *bitmapGlyph = std::get_if<Glyph::Bitmap>(&result.at(i).glyph)) {
494 for (
int b = 0;
b < bitmapGlyph->images.size();
b++) {
495 QImage img = bitmapGlyph->images.at(b);
496 QRectF drawRect = bitmapGlyph->drawRects.at(b);
498 QTransform imageTf = QTransform::fromTranslate(drawRect.x(), drawRect.y());
499 QTransform viewBox = QTransform::fromScale(drawRect.width()/img.width(),
500 drawRect.height()/img.height());
502 params.
setProperty(imageViewTransformProp, viewBox);
504 if (img.format() == QImage::Format_Grayscale8 || img.format() == QImage::Format_Mono) {
506 shape->
setSize(drawRect.size());
507 rect->setSize(drawRect.size());
508 rect->setStroke(
nullptr);
511 rect->setClipMask(mask);
512 rect->setZIndex(shapes.size());
515 tf.mapRect(drawRect)));
516 rect->setTransformation(imageTf*tf);
519 rect->setInheritBackground(currentNodeInheritsBg);
520 rect->setInheritStroke(currentNodeInheritsStroke);
522 shape->
setSize(drawRect.size());
525 shapes.append(shape);
543 shapes.append(shape);
553 currentNodeInheritsBg =
true;
554 currentNodeInheritsStroke =
true;
571 shapes.append(shape);
572 if (currentNodeInheritsBg && !textDecorationColor.isValid()) {
581 if (shapes.size() == 1) {
582 parentShape = shapes.first();
583 }
else if (shapes.size() > 1) {
603void KoSvgTextShape::Private::paintDebug(QPainter &painter,
608 for (
auto it = textData.depthFirstTailBegin(); it != textData.depthFirstTailEnd(); it++) {
609 const int j = it->finalResultIndex;
610 if (currentIndex > result.size())
continue;
611 if (j < 0 || j > result.size())
continue;
613 const QRect shapeGlobalClipRect = painter.transform().mapRect(it->associatedOutline.boundingRect()).toAlignedRect();
617 QFont font(QFont(), painter.device());
618 font.setPointSizeF(16.0);
620 if (shapeGlobalClipRect.isValid() && childCount(
siblingCurrent(it)) == 0) {
621 for (
int i = currentIndex; i < j; i++) {
622 if (result.at(i).addressable && !result.at(i).hidden) {
623 const QTransform tf = result.at(i).finalTransform();
626 painter.setBrush(Qt::transparent);
627 QPen pen(QColor(0, 0, 0, 50));
628 pen.setCosmetic(
true);
631 if (
const auto *bitmapGlyph = std::get_if<Glyph::Bitmap>(&result.at(i).glyph)) {
632 Q_FOREACH(
const QRectF drawRect, bitmapGlyph->drawRects) {
633 painter.drawPolygon(tf.map(drawRect));
635 }
else if (
const auto *colorGlyph = std::get_if<Glyph::ColorLayers>(&result.at(i).glyph)) {
637 Q_FOREACH (
const QPainterPath &
p, colorGlyph->paths) {
641 }
else if (
const auto *outlineGlyph = std::get_if<Glyph::Outline>(&result.at(i).glyph)) {
642 painter.drawPolygon(tf.map(outlineGlyph->path.boundingRect()));
644 QColor penColor = result.at(i).anchored_chunk ? result.at(i).isHanging ? Qt::red : Qt::magenta
647 penColor.setAlpha(192);
648 pen.setColor(penColor);
650 painter.drawPolygon(tf.map(result.at(i).layoutBox()));
652 penColor.setAlpha(96);
653 pen.setColor(penColor);
655 pen.setStyle(Qt::DotLine);
657 painter.drawPolygon(tf.map(result.at(i).lineHeightBox()));
659 pen.setStyle(Qt::SolidLine);
662 penColor.setAlpha(192);
663 pen.setColor(penColor);
665 painter.drawLine(tf.map(result.at(i).cursorInfo.caret));
668 const QPointF center = tf.mapRect(result.at(i).layoutBox()).center();
670 text += QString::number(i);
674 while (end < result.size() && result[end].middle) {
680 text += QString::number(end);
683 text += QString(
"\n(%1)").arg(result.at(i).plaintTextIndex);
684 painter.setWorldMatrixEnabled(
false);
685 painter.setPen(Qt::red);
686 painter.drawText(QRectF(painter.transform().map(center), QSizeF(0, 64)).adjusted(-128, 0, 128, 0),
687 Qt::AlignHCenter | Qt::AlignTop,
689 painter.setWorldMatrixEnabled(
true);
692 const BreakType breakType = result.at(i).breakType;
699 penColor.setAlpha(128);
700 pen.setColor(penColor);
702 painter.drawPoint(center);
705 penColor = Qt::darkGreen;
706 penColor.setAlpha(192);
707 pen.setColor(penColor);
710 for (
int k=0; k<offset.size(); k++) {
711 painter.drawPoint(tf.map(offset.at(k)));
715 penColor.setAlpha(192);
716 pen.setColor(penColor);
718 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)
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.
KoShapeStrokeModelSP stroke() const override
QSharedPointer< KoShapeBackground > background() const override
QVector< PaintOrder > paintOrder() const override
paintOrder
QRectF outlineRect() const override
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.