QString KoOdfGraphicStyles::saveOdfGradientStyle(KoGenStyles &mainStyles, const QBrush &brush) { KoGenStyle gradientStyle; if (brush.style() == Qt::RadialGradientPattern) { const QRadialGradient *gradient = static_cast<const QRadialGradient*>(brush.gradient()); gradientStyle = KoGenStyle(KoGenStyle::RadialGradientStyle /*no family name*/); gradientStyle.addAttributePercent("svg:cx", gradient->center().x() * 100); gradientStyle.addAttributePercent("svg:cy", gradient->center().y() * 100); gradientStyle.addAttributePercent("svg:r", gradient->radius() * 100); gradientStyle.addAttributePercent("svg:fx", gradient->focalPoint().x() * 100); gradientStyle.addAttributePercent("svg:fy", gradient->focalPoint().y() * 100); } else if (brush.style() == Qt::LinearGradientPattern) { const QLinearGradient *gradient = static_cast<const QLinearGradient*>(brush.gradient()); gradientStyle = KoGenStyle(KoGenStyle::LinearGradientStyle /*no family name*/); gradientStyle.addAttributePercent("svg:x1", gradient->start().x() * 100); gradientStyle.addAttributePercent("svg:y1", gradient->start().y() * 100); gradientStyle.addAttributePercent("svg:x2", gradient->finalStop().x() * 100); gradientStyle.addAttributePercent("svg:y2", gradient->finalStop().y() * 100); } else if (brush.style() == Qt::ConicalGradientPattern) { const QConicalGradient * gradient = static_cast<const QConicalGradient*>(brush.gradient()); gradientStyle = KoGenStyle(KoGenStyle::ConicalGradientStyle /*no family name*/); gradientStyle.addAttributePercent("svg:cx", gradient->center().x() * 100); gradientStyle.addAttributePercent("svg:cy", gradient->center().y() * 100); gradientStyle.addAttribute("draw:angle", QString("%1").arg(gradient->angle())); } const QGradient * gradient = brush.gradient(); if (gradient->spread() == QGradient::RepeatSpread) gradientStyle.addAttribute("svg:spreadMethod", "repeat"); else if (gradient->spread() == QGradient::ReflectSpread) gradientStyle.addAttribute("svg:spreadMethod", "reflect"); else gradientStyle.addAttribute("svg:spreadMethod", "pad"); if (! brush.transform().isIdentity()) { gradientStyle.addAttribute("svg:gradientTransform", saveTransformation(brush.transform())); } QBuffer buffer; buffer.open(QIODevice::WriteOnly); KoXmlWriter elementWriter(&buffer); // TODO pass indentation level // save stops QGradientStops stops = gradient->stops(); Q_FOREACH (const QGradientStop & stop, stops) { elementWriter.startElement("svg:stop"); elementWriter.addAttribute("svg:offset", QString("%1").arg(stop.first)); elementWriter.addAttribute("svg:stop-color", stop.second.name()); if (stop.second.alphaF() < 1.0) elementWriter.addAttribute("svg:stop-opacity", QString("%1").arg(stop.second.alphaF())); elementWriter.endElement(); }
void QEmulationPaintEngine::stroke(const QVectorPath &path, const QPen &pen) { QPainterState *s = state(); if (s->bgMode == Qt::OpaqueMode && pen.style() > Qt::SolidLine) { QPen bgPen = pen; bgPen.setBrush(s->bgBrush); bgPen.setStyle(Qt::SolidLine); real_engine->stroke(path, bgPen); } QBrush brush = pen.brush(); QPen copy = pen; Qt::BrushStyle style = qbrush_style(brush); if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) { const QGradient *g = brush.gradient(); if (g->coordinateMode() > QGradient::LogicalMode) { if (g->coordinateMode() == QGradient::StretchToDeviceMode) { QTransform mat = brush.transform(); mat.scale(real_engine->painter()->device()->width(), real_engine->painter()->device()->height()); brush.setTransform(mat); copy.setBrush(brush); real_engine->stroke(path, copy); return; } else if (g->coordinateMode() == QGradient::ObjectBoundingMode) { QTransform mat = brush.transform(); QRectF r = path.controlPointRect(); mat.translate(r.x(), r.y()); mat.scale(r.width(), r.height()); brush.setTransform(mat); copy.setBrush(brush); real_engine->stroke(path, copy); return; } } } real_engine->stroke(path, pen); }
void QEmulationPaintEngine::fill(const QVectorPath &path, const QBrush &brush) { QPainterState *s = state(); if (s->bgMode == Qt::OpaqueMode) { Qt::BrushStyle style = brush.style(); if (style >= Qt::Dense1Pattern && style <= Qt::DiagCrossPattern) real_engine->fill(path, s->bgBrush); } Qt::BrushStyle style = qbrush_style(brush); if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) { const QGradient *g = brush.gradient(); if (g->coordinateMode() > QGradient::LogicalMode) { if (g->coordinateMode() == QGradient::StretchToDeviceMode) { QBrush copy = brush; QTransform mat = copy.transform(); mat.scale(real_engine->painter()->device()->width(), real_engine->painter()->device()->height()); copy.setTransform(mat); real_engine->fill(path, copy); return; } else if (g->coordinateMode() == QGradient::ObjectBoundingMode) { QBrush copy = brush; QTransform mat = copy.transform(); QRectF r = path.controlPointRect(); mat.translate(r.x(), r.y()); mat.scale(r.width(), r.height()); copy.setTransform(mat); real_engine->fill(path, copy); return; } } } real_engine->fill(path, brush); }
bool KGradientBackground::loadStyle(KOdfLoadingContext &context, const QSizeF &shapeSize) { Q_D(KGradientBackground); KOdfStyleStack &styleStack = context.styleStack(); if (! styleStack.hasProperty(KOdfXmlNS::draw, "fill")) return false; QString fillStyle = styleStack.property(KOdfXmlNS::draw, "fill"); if (fillStyle == "gradient") { QBrush brush = KOdf::loadOdfGradientStyle(styleStack, context.stylesReader(), shapeSize); const QGradient * gradient = brush.gradient(); if (gradient) { d->gradient = KFlake::cloneGradient(gradient); d->matrix = brush.transform(); return true; } } return false; }
void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) { #ifdef QT_DEBUG_DRAW qDebug() << "QPaintEngineEx::stroke()" << pen; #endif Q_D(QPaintEngineEx); if (path.isEmpty()) return; if (!d->strokeHandler) { d->strokeHandler = new StrokeHandler(path.elementCount()+4); d->stroker.setMoveToHook(qpaintengineex_moveTo); d->stroker.setLineToHook(qpaintengineex_lineTo); d->stroker.setCubicToHook(qpaintengineex_cubicTo); } if (!qpen_fast_equals(pen, d->strokerPen)) { d->strokerPen = pen; d->stroker.setJoinStyle(pen.joinStyle()); d->stroker.setCapStyle(pen.capStyle()); d->stroker.setMiterLimit(pen.miterLimit()); qreal penWidth = pen.widthF(); if (penWidth == 0) d->stroker.setStrokeWidth(1); else d->stroker.setStrokeWidth(penWidth); Qt::PenStyle style = pen.style(); if (style == Qt::SolidLine) { d->activeStroker = &d->stroker; } else if (style == Qt::NoPen) { d->activeStroker = 0; } else { d->dasher.setDashPattern(pen.dashPattern()); d->dasher.setDashOffset(pen.dashOffset()); d->activeStroker = &d->dasher; } } if (!d->activeStroker) { return; } if (pen.style() > Qt::SolidLine) { if (pen.isCosmetic()) { d->activeStroker->setClipRect(d->exDeviceRect); } else { QRectF clipRect = state()->matrix.inverted().mapRect(QRectF(d->exDeviceRect)); d->activeStroker->setClipRect(clipRect); } } const QPainterPath::ElementType *types = path.elements(); const qreal *points = path.points(); int pointCount = path.elementCount(); const qreal *lastPoint = points + (pointCount<<1); d->strokeHandler->types.reset(); d->strokeHandler->pts.reset(); // Some engines might decide to optimize for the non-shape hint later on... uint flags = QVectorPath::WindingFill; if (path.elementCount() > 2) flags |= QVectorPath::NonConvexShapeMask; if (d->stroker.capStyle() == Qt::RoundCap || d->stroker.joinStyle() == Qt::RoundJoin) flags |= QVectorPath::CurvedShapeMask; // ### Perspective Xforms are currently not supported... if (!pen.isCosmetic()) { // We include cosmetic pens in this case to avoid having to // change the current transform. Normal transformed, // non-cosmetic pens will be transformed as part of fill // later, so they are also covered here.. d->activeStroker->setCurveThresholdFromTransform(state()->matrix); d->activeStroker->begin(d->strokeHandler); if (types) { while (points < lastPoint) { switch (*types) { case QPainterPath::MoveToElement: d->activeStroker->moveTo(points[0], points[1]); points += 2; ++types; break; case QPainterPath::LineToElement: d->activeStroker->lineTo(points[0], points[1]); points += 2; ++types; break; case QPainterPath::CurveToElement: d->activeStroker->cubicTo(points[0], points[1], points[2], points[3], points[4], points[5]); points += 6; types += 3; flags |= QVectorPath::CurvedShapeMask; break; default: break; } } if (path.hasImplicitClose()) d->activeStroker->lineTo(path.points()[0], path.points()[1]); } else { d->activeStroker->moveTo(points[0], points[1]); points += 2; while (points < lastPoint) { d->activeStroker->lineTo(points[0], points[1]); points += 2; } if (path.hasImplicitClose()) d->activeStroker->lineTo(path.points()[0], path.points()[1]); } d->activeStroker->end(); if (!d->strokeHandler->types.size()) // an empty path... return; QVectorPath strokePath(d->strokeHandler->pts.data(), d->strokeHandler->types.size(), d->strokeHandler->types.data(), flags); fill(strokePath, pen.brush()); } else { // For cosmetic pens we need a bit of trickery... We to process xform the input points if (state()->matrix.type() >= QTransform::TxProject) { QPainterPath painterPath = state()->matrix.map(path.convertToPainterPath()); d->activeStroker->strokePath(painterPath, d->strokeHandler, QTransform()); } else { d->activeStroker->setCurveThresholdFromTransform(QTransform()); d->activeStroker->begin(d->strokeHandler); if (types) { while (points < lastPoint) { switch (*types) { case QPainterPath::MoveToElement: { QPointF pt = (*(QPointF *) points) * state()->matrix; d->activeStroker->moveTo(pt.x(), pt.y()); points += 2; ++types; break; } case QPainterPath::LineToElement: { QPointF pt = (*(QPointF *) points) * state()->matrix; d->activeStroker->lineTo(pt.x(), pt.y()); points += 2; ++types; break; } case QPainterPath::CurveToElement: { QPointF c1 = ((QPointF *) points)[0] * state()->matrix; QPointF c2 = ((QPointF *) points)[1] * state()->matrix; QPointF e = ((QPointF *) points)[2] * state()->matrix; d->activeStroker->cubicTo(c1.x(), c1.y(), c2.x(), c2.y(), e.x(), e.y()); points += 6; types += 3; flags |= QVectorPath::CurvedShapeMask; break; } default: break; } } if (path.hasImplicitClose()) { QPointF pt = * ((QPointF *) path.points()) * state()->matrix; d->activeStroker->lineTo(pt.x(), pt.y()); } } else { QPointF p = ((QPointF *)points)[0] * state()->matrix; d->activeStroker->moveTo(p.x(), p.y()); points += 2; while (points < lastPoint) { QPointF p = ((QPointF *)points)[0] * state()->matrix; d->activeStroker->lineTo(p.x(), p.y()); points += 2; } if (path.hasImplicitClose()) d->activeStroker->lineTo(p.x(), p.y()); } d->activeStroker->end(); } QVectorPath strokePath(d->strokeHandler->pts.data(), d->strokeHandler->types.size(), d->strokeHandler->types.data(), flags); QTransform xform = state()->matrix; state()->matrix = QTransform(); transformChanged(); QBrush brush = pen.brush(); if (qbrush_style(brush) != Qt::SolidPattern) brush.setTransform(brush.transform() * xform); fill(strokePath, brush); state()->matrix = xform; transformChanged(); } }
void QBlitterPaintEngine::fillRect(const QRectF &rect, const QBrush &brush) { if (rect.size().isEmpty()) return; Q_D(QBlitterPaintEngine); if (qbrush_style(brush) == Qt::SolidPattern && d->caps.canBlitterAlphaFillRect()) { d->fillRect(rect, qbrush_color(brush), true); } else if (qbrush_style(brush) == Qt::SolidPattern && qbrush_color(brush).alpha() == 0xff && d->caps.canBlitterFillRect()) { d->fillRect(rect, qbrush_color(brush), false); } else if ((brush.style() == Qt::TexturePattern) && (brush.transform().type() <= QTransform::TxTranslate) && ((d->caps.canBlitterDrawPixmapOpacity(brush.texture())) || (d->caps.canBlitterDrawPixmap(rect, brush.texture(), rect)))) { bool rectIsFilled = false; QRectF transformedRect = state()->matrix.mapRect(rect); qreal x = transformedRect.x(); qreal y = transformedRect.y(); QPixmap pm = brush.texture(); d->unlock(); int srcX = int(rect.x() - state()->brushOrigin.x() - brush.transform().dx()) % pm.width(); if (srcX < 0) srcX = pm.width() + srcX; const int startX = srcX; int srcY = int(rect.y() - state()->brushOrigin.y() - brush.transform().dy()) % pm.height(); if (srcY < 0) srcY = pm.height() + srcY; while (!rectIsFilled) { qreal blitWidth = (pm.width() ) - srcX; qreal blitHeight = (pm.height() ) - srcY; if (x + blitWidth > transformedRect.right()) blitWidth = transformedRect.right() -x; if (y + blitHeight > transformedRect.bottom()) blitHeight = transformedRect.bottom() - y; const QClipData *clipData = d->clip(); if (clipData->hasRectClip) { QRect targetRect = QRect(x, y, blitWidth, blitHeight).intersected(clipData->clipRect); if (targetRect.isValid()) { int tmpSrcX = srcX + (targetRect.x() - x); int tmpSrcY = srcY + (targetRect.y() - y); QRect srcRect(tmpSrcX, tmpSrcY, targetRect.width(), targetRect.height()); d->pmData->blittable()->drawPixmap(targetRect, pm, srcRect); } } else if (clipData->hasRegionClip) { QVector<QRect> clipRects = clipData->clipRegion.rects(); QRect unclippedTargetRect(x, y, blitWidth, blitHeight); QRegion intersectedRects = clipData->clipRegion.intersected(unclippedTargetRect); for (int i = 0; i < intersectedRects.rects().size(); ++i) { QRect targetRect = intersectedRects.rects().at(i); if (!targetRect.isValid() || targetRect.isEmpty()) continue; int tmpSrcX = srcX + (targetRect.x() - x); int tmpSrcY = srcY + (targetRect.y() - y); QRect srcRect(tmpSrcX, tmpSrcY, targetRect.width(), targetRect.height()); d->pmData->blittable()->drawPixmap(targetRect, pm, srcRect); } } x+=blitWidth; if (qFuzzyCompare(x, transformedRect.right())) { x = transformedRect.x(); srcX = startX; srcY = 0; y += blitHeight; if (qFuzzyCompare(y, transformedRect.bottom())) rectIsFilled = true; } else srcX = 0; } } else { d->lock(); d->pmData->markRasterOverlay(rect); QRasterPaintEngine::fillRect(rect, brush); } }
ComPtr<ID2D1Brush> to_d2d_brush(const QBrush &newBrush, bool *needsEmulation) { HRESULT hr; ComPtr<ID2D1Brush> result; Q_ASSERT(needsEmulation); *needsEmulation = false; switch (newBrush.style()) { case Qt::NoBrush: break; case Qt::SolidPattern: { ComPtr<ID2D1SolidColorBrush> solid; hr = dc()->CreateSolidColorBrush(to_d2d_color_f(newBrush.color()), &solid); if (FAILED(hr)) { qWarning("%s: Could not create solid color brush: %#x", __FUNCTION__, hr); break; } hr = solid.As(&result); if (FAILED(hr)) qWarning("%s: Could not convert solid color brush: %#x", __FUNCTION__, hr); } break; case Qt::Dense1Pattern: case Qt::Dense2Pattern: case Qt::Dense3Pattern: case Qt::Dense4Pattern: case Qt::Dense5Pattern: case Qt::Dense6Pattern: case Qt::Dense7Pattern: case Qt::HorPattern: case Qt::VerPattern: case Qt::CrossPattern: case Qt::BDiagPattern: case Qt::FDiagPattern: case Qt::DiagCrossPattern: { ComPtr<ID2D1BitmapBrush1> bitmapBrush; D2D1_BITMAP_BRUSH_PROPERTIES1 bitmapBrushProperties = { D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP, interpolationMode() }; QImage brushImg = qt_imageForBrush(newBrush.style(), false); brushImg.setColor(0, newBrush.color().rgba()); brushImg.setColor(1, qRgba(0, 0, 0, 0)); QWindowsDirect2DBitmap bitmap; bool success = bitmap.fromImage(brushImg, Qt::AutoColor); if (!success) { qWarning("%s: Could not create Direct2D bitmap from Qt pattern brush image", __FUNCTION__); break; } hr = dc()->CreateBitmapBrush(bitmap.bitmap(), bitmapBrushProperties, &bitmapBrush); if (FAILED(hr)) { qWarning("%s: Could not create Direct2D bitmap brush for Qt pattern brush: %#x", __FUNCTION__, hr); break; } hr = bitmapBrush.As(&result); if (FAILED(hr)) qWarning("%s: Could not convert Direct2D bitmap brush for Qt pattern brush: %#x", __FUNCTION__, hr); } break; case Qt::LinearGradientPattern: case Qt::RadialGradientPattern: case Qt::ConicalGradientPattern: *needsEmulation = true; break; case Qt::TexturePattern: { ComPtr<ID2D1BitmapBrush1> bitmapBrush; D2D1_BITMAP_BRUSH_PROPERTIES1 bitmapBrushProperties = { D2D1_EXTEND_MODE_WRAP, D2D1_EXTEND_MODE_WRAP, interpolationMode() }; QWindowsDirect2DPlatformPixmap *pp = static_cast<QWindowsDirect2DPlatformPixmap *>(newBrush.texture().handle()); QWindowsDirect2DBitmap *bitmap = pp->bitmap(); hr = dc()->CreateBitmapBrush(bitmap->bitmap(), bitmapBrushProperties, &bitmapBrush); if (FAILED(hr)) { qWarning("%s: Could not create texture brush: %#x", __FUNCTION__, hr); break; } hr = bitmapBrush.As(&result); if (FAILED(hr)) qWarning("%s: Could not convert texture brush: %#x", __FUNCTION__, hr); } break; } if (result && !newBrush.transform().isIdentity()) result->SetTransform(to_d2d_matrix_3x2_f(newBrush.transform())); return result; }