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);
372 const QString imageProp =
"image";
373 const QString imageViewTransformProp =
"viewboxTransform";
380 bool currentNodeInheritsBg =
false;
381 bool currentNodeInheritsStroke =
false;
386 QMap<KoSvgText::TextDecoration, QPainterPath> textDecorations = it->textDecorations;
394 stroke->strokeInsets(rootShape, insets);
418 shapes.append(shape);
419 if (currentNodeInheritsBg && !textDecorationColor.isValid()) {
436 shapes.append(shape);
437 if (currentNodeInheritsBg && !textDecorationColor.isValid()) {
446 const int j = it->finalResultIndex;
447 if (j < 0 || j > result.size())
continue;
448 for (
int i = currentIndex; i < j; i++) {
449 if (result.at(i).addressable && !result.at(i).hidden) {
450 const QTransform tf = result.at(i).finalTransform();
451 if (
const auto *colorGlyph = std::get_if<Glyph::ColorLayers>(&result.at(i).glyph)) {
452 for (
int c = 0; c < colorGlyph->paths.size(); c++) {
453 QBrush color = colorGlyph->colors.at(c);
454 bool replace = colorGlyph->replaceWithForeGroundColor.at(c);
467 shapes.append(shape);
468 if (replace && currentNodeInheritsBg) {
473 }
else if (
const auto *outlineGlyph = std::get_if<Glyph::Outline>(&result.at(i).glyph)) {
474 chunk.addPath(tf.map(outlineGlyph->path));
475 }
else if (
const auto *bitmapGlyph = std::get_if<Glyph::Bitmap>(&result.at(i).glyph)) {
477 for (
int b = 0;
b < bitmapGlyph->images.size();
b++) {
478 QImage img = bitmapGlyph->images.at(b);
479 QRectF drawRect = bitmapGlyph->drawRects.at(b);
481 QTransform imageTf = QTransform::fromTranslate(drawRect.x(), drawRect.y());
482 QTransform viewBox = QTransform::fromScale(drawRect.width()/img.width(),
483 drawRect.height()/img.height());
485 params.
setProperty(imageViewTransformProp, viewBox);
487 if (img.format() == QImage::Format_Grayscale8 || img.format() == QImage::Format_Mono) {
489 shape->
setSize(drawRect.size());
490 rect->setSize(drawRect.size());
491 rect->setStroke(
nullptr);
494 rect->setClipMask(mask);
495 rect->setZIndex(shapes.size());
498 tf.mapRect(drawRect)));
499 rect->setTransformation(imageTf*tf);
502 rect->setInheritBackground(currentNodeInheritsBg);
503 rect->setInheritStroke(currentNodeInheritsStroke);
505 shape->
setSize(drawRect.size());
508 shapes.append(shape);
526 shapes.append(shape);
536 currentNodeInheritsBg =
true;
537 currentNodeInheritsStroke =
true;
554 shapes.append(shape);
555 if (currentNodeInheritsBg && !textDecorationColor.isValid()) {
564 if (shapes.size() == 1) {
565 parentShape = shapes.first();
566 }
else if (shapes.size() > 1) {
586void KoSvgTextShape::Private::paintDebug(QPainter &painter,
591 for (
auto it = textData.depthFirstTailBegin(); it != textData.depthFirstTailEnd(); it++) {
592 const int j = it->finalResultIndex;
593 if (currentIndex > result.size())
continue;
594 if (j < 0 || j > result.size())
continue;
596 const QRect shapeGlobalClipRect = painter.transform().mapRect(it->associatedOutline.boundingRect()).toAlignedRect();
600 QFont font(QFont(), painter.device());
601 font.setPointSizeF(16.0);
603 if (shapeGlobalClipRect.isValid() && childCount(
siblingCurrent(it)) == 0) {
604 for (
int i = currentIndex; i < j; i++) {
605 if (result.at(i).addressable && !result.at(i).hidden) {
606 const QTransform tf = result.at(i).finalTransform();
609 painter.setBrush(Qt::transparent);
610 QPen pen(QColor(0, 0, 0, 50));
611 pen.setCosmetic(
true);
614 if (
const auto *bitmapGlyph = std::get_if<Glyph::Bitmap>(&result.at(i).glyph)) {
615 Q_FOREACH(
const QRectF drawRect, bitmapGlyph->drawRects) {
616 painter.drawPolygon(tf.map(drawRect));
618 }
else if (
const auto *colorGlyph = std::get_if<Glyph::ColorLayers>(&result.at(i).glyph)) {
620 Q_FOREACH (
const QPainterPath &
p, colorGlyph->paths) {
624 }
else if (
const auto *outlineGlyph = std::get_if<Glyph::Outline>(&result.at(i).glyph)) {
625 painter.drawPolygon(tf.map(outlineGlyph->path.boundingRect()));
627 QColor penColor = result.at(i).anchored_chunk ? result.at(i).isHanging ? Qt::red : Qt::magenta
630 penColor.setAlpha(192);
631 pen.setColor(penColor);
633 painter.drawPolygon(tf.map(result.at(i).layoutBox()));
635 penColor.setAlpha(96);
636 pen.setColor(penColor);
638 pen.setStyle(Qt::DotLine);
640 painter.drawPolygon(tf.map(result.at(i).lineHeightBox()));
642 pen.setStyle(Qt::SolidLine);
645 penColor.setAlpha(192);
646 pen.setColor(penColor);
648 painter.drawLine(tf.map(result.at(i).cursorInfo.caret));
651 const QPointF center = tf.mapRect(result.at(i).layoutBox()).center();
653 text += QString::number(i);
657 while (end < result.size() && result[end].middle) {
663 text += QString::number(end);
666 text += QString(
"\n(%1)").arg(result.at(i).plaintTextIndex);
667 painter.setWorldMatrixEnabled(
false);
668 painter.setPen(Qt::red);
669 painter.drawText(QRectF(painter.transform().map(center), QSizeF(0, 64)).adjusted(-128, 0, 128, 0),
670 Qt::AlignHCenter | Qt::AlignTop,
672 painter.setWorldMatrixEnabled(
true);
675 const BreakType breakType = result.at(i).breakType;
682 penColor.setAlpha(128);
683 pen.setColor(penColor);
685 painter.drawPoint(center);
688 penColor = Qt::darkGreen;
689 penColor.setAlpha(192);
690 pen.setColor(penColor);
693 for (
int k=0; k<offset.size(); k++) {
694 painter.drawPoint(tf.map(offset.at(k)));
698 penColor.setAlpha(192);
699 pen.setColor(penColor);
701 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
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 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.