void SchemeSensors::paintEvent(QPaintEvent *) { QPainter schemePainter(this); schemePainter.setRenderHint(QPainter::Antialiasing, true); schemePainter.setBrush(QBrush(Qt::gray, Qt::DiagCrossPattern)); schemePainter.setPen(QPen(QColor(0, 153, 204), 2)); /* Draw Rects */ schemePainter.drawRect(QRect(30, 5, width() - 60, height() / 8)); schemePainter.drawRect(QRect(100, 5 + height() / 8, width() - 200, (height() / 4) + (height() / 8))); /* Draw Polygon */ QPolygonF polygon; polygon << QPointF(10, (5 + height() / 8) + (height() / 4) + (height() / 8)); polygon << QPointF(width() - 20, (5 + height() / 8) + (height() / 4) + (height() / 8)); polygon << QPointF(width() - 20, 105 + (height() / 2)); polygon << QPointF(width() / 2, 205 + (height() / 2)); polygon << QPointF(10, 105 + (height() / 2)); polygon << QPointF(10, (5 + height() / 8) + (height() / 4) + (height() / 8)); schemePainter.drawPolygon(polygon); /* Draw Text */ QPainter textPainter(this); drawRotateText(&textPainter, 270, 25, (height() / 8) - 5, blockA); drawRotateText(&textPainter, 270, 95, ((height() / 4) + (height() / 8)) - 5, blockB); drawRotateText(&textPainter, 90, width() - 15, (30 + height() / 8) + (height() / 4) + (height() / 8), blockC); if (qDrawSensors) { drawSensors(); } }
void EllipsisBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom) { GraphicsContext* context = paintInfo.context; RenderStyle* style = renderer().style(isFirstLineStyle()); const Font& font = style->font(); FloatPoint boxOrigin = locationIncludingFlipping(); boxOrigin.moveBy(FloatPoint(paintOffset)); if (!isHorizontal()) boxOrigin.move(0, -virtualLogicalHeight()); FloatRect boxRect(boxOrigin, LayoutSize(logicalWidth(), virtualLogicalHeight())); GraphicsContextStateSaver stateSaver(*context); if (!isHorizontal()) context->concatCTM(InlineTextBox::rotation(boxRect, InlineTextBox::Clockwise)); FloatPoint textOrigin(boxOrigin.x(), boxOrigin.y() + font.fontMetrics().ascent()); bool isPrinting = renderer().document().printing(); bool haveSelection = !isPrinting && paintInfo.phase != PaintPhaseTextClip && selectionState() != RenderObject::SelectionNone; if (haveSelection) paintSelection(context, boxOrigin, style, font); else if (paintInfo.phase == PaintPhaseSelection) return; TextPainter::Style textStyle = TextPainter::textPaintingStyle(renderer(), style, paintInfo.forceBlackText(), isPrinting); if (haveSelection) textStyle = TextPainter::selectionPaintingStyle(renderer(), true, paintInfo.forceBlackText(), isPrinting, textStyle); TextRun textRun = constructTextRun(&renderer(), font, m_str, style, TextRun::AllowTrailingExpansion); TextPainter textPainter(context, font, textRun, textOrigin, boxRect, isHorizontal()); textPainter.paint(0, m_str.length(), m_str.length(), textStyle); paintMarkupBox(paintInfo, paintOffset, lineTop, lineBottom, style); }
void paintFlow(const RenderBlockFlow& flow, const Layout& layout, PaintInfo& paintInfo, const LayoutPoint& paintOffset) { if (paintInfo.phase != PaintPhaseForeground) return; RenderStyle& style = flow.style(); if (style.visibility() != VISIBLE) return; bool debugBordersEnabled = flow.frame().settings().simpleLineLayoutDebugBordersEnabled(); TextPainter textPainter(paintInfo.context()); textPainter.setFont(style.fontCascade()); textPainter.setTextPaintStyle(computeTextPaintStyle(flow.frame(), style, paintInfo)); Optional<TextDecorationPainter> textDecorationPainter; if (style.textDecorationsInEffect() != TextDecorationNone) { const RenderText* textRenderer = childrenOfType<RenderText>(flow).first(); if (textRenderer) { textDecorationPainter = TextDecorationPainter(paintInfo.context(), style.textDecorationsInEffect(), *textRenderer, false); textDecorationPainter->setFont(style.fontCascade()); textDecorationPainter->setBaseline(style.fontMetrics().ascent()); } } LayoutRect paintRect = paintInfo.rect; paintRect.moveBy(-paintOffset); auto resolver = runResolver(flow, layout); float strokeOverflow = std::ceil(flow.style().textStrokeWidth()); float deviceScaleFactor = flow.document().deviceScaleFactor(); for (auto run : resolver.rangeForRect(paintRect)) { if (run.start() == run.end()) continue; FloatRect rect = run.rect(); FloatRect visualOverflowRect = rect; visualOverflowRect.inflate(strokeOverflow); if (paintRect.y() > visualOverflowRect.maxY() || paintRect.maxY() < visualOverflowRect.y()) continue; TextRun textRun(run.text()); textRun.setTabSize(!style.collapseWhiteSpace(), style.tabSize()); // x position indicates the line offset from the rootbox. It's always 0 in case of simple line layout. textRun.setXPos(0); FloatPoint textOrigin = FloatPoint(rect.x() + paintOffset.x(), roundToDevicePixel(run.baselinePosition() + paintOffset.y(), deviceScaleFactor)); textPainter.paintText(textRun, textRun.length(), rect, textOrigin); if (textDecorationPainter) { textDecorationPainter->setWidth(rect.width()); textDecorationPainter->paintTextDecoration(textRun, textOrigin, rect.location() + paintOffset); } if (debugBordersEnabled) paintDebugBorders(paintInfo.context(), LayoutRect(run.rect()), paintOffset); } }
void EllipsisBoxPainter::paintEllipsis(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom, const ComputedStyle& style) { bool haveSelection = !paintInfo.isPrinting() && paintInfo.phase != PaintPhaseTextClip && m_ellipsisBox.getSelectionState() != SelectionNone; LayoutRect paintRect(m_ellipsisBox.logicalFrameRect()); if (haveSelection) paintRect.unite(LayoutRect(m_ellipsisBox.selectionRect())); m_ellipsisBox.logicalRectToPhysicalRect(paintRect); paintRect.moveBy(paintOffset); GraphicsContext& context = paintInfo.context; DisplayItem::Type displayItemType = DisplayItem::paintPhaseToDrawingType(paintInfo.phase); if (DrawingRecorder::useCachedDrawingIfPossible(context, m_ellipsisBox, displayItemType)) return; DrawingRecorder recorder(context, m_ellipsisBox, displayItemType, FloatRect(paintRect)); LayoutPoint boxOrigin = m_ellipsisBox.locationIncludingFlipping(); boxOrigin.moveBy(paintOffset); LayoutRect boxRect(boxOrigin, LayoutSize(m_ellipsisBox.logicalWidth(), m_ellipsisBox.virtualLogicalHeight())); GraphicsContextStateSaver stateSaver(context); if (!m_ellipsisBox.isHorizontal()) context.concatCTM(TextPainter::rotation(boxRect, TextPainter::Clockwise)); const Font& font = style.font(); if (haveSelection) paintSelection(context, boxOrigin, style, font); else if (paintInfo.phase == PaintPhaseSelection) return; TextPainter::Style textStyle = TextPainter::textPaintingStyle(m_ellipsisBox.getLineLayoutItem(), style, paintInfo); if (haveSelection) textStyle = TextPainter::selectionPaintingStyle(m_ellipsisBox.getLineLayoutItem(), true, paintInfo, textStyle); TextRun textRun = constructTextRun(font, m_ellipsisBox.ellipsisStr(), style, TextRun::AllowTrailingExpansion); LayoutPoint textOrigin(boxOrigin.x(), boxOrigin.y() + font.getFontMetrics().ascent()); TextPainter textPainter(context, font, textRun, textOrigin, boxRect, m_ellipsisBox.isHorizontal()); textPainter.paint(0, m_ellipsisBox.ellipsisStr().length(), m_ellipsisBox.ellipsisStr().length(), textStyle); }
bool ImageStackPainter::draw( const util::rect<double>& roi, const util::point<double>& resolution) { LOG_ALL(imagestackpainterlog) << "redrawing section " << _section << std::endl; if (_showColored) { for (unsigned int i = 0; i < _stack->size(); i++) { _imagePainters[i]->draw(roi, resolution); } } else { for (unsigned int i = 0; i < _numImages; i++) { double d = static_cast<int>(i - _numImages/2)*(_imageHeight + _gap); glTranslated(0, -d, 0); _imagePainters[i]->draw(roi - util::point<double>(static_cast<double>(0), -d), resolution); glTranslated(0, d, 0); } } if (_annotation != "") { gui::TextPainter textPainter(_annotation); glTranslatef( _annotationX, _annotationY, 0.0f); textPainter.draw(roi - util::point<double>(_annotationX, _annotationY), resolution); glTranslatef(-_annotationX, -_annotationY, 0.0f); } return false; }
QImage RichTextRenderer::renderText() { // qDebug()<<itemName()<<"TextBoxWarmingThread::run(): htmlCode:"<<htmlCode; //qDebug() << "RichTextRenderer::renderText(): HTML:"<<html(); //qDebug() << "RichTextRenderer::update(): Update Start..."; //qDebug() << "RichTextRenderer::renderText(): \t in thread:"<<QThread::currentThreadId(); if(m_updateTimer.isActive()) m_updateTimer.stop(); QTime renderTime; renderTime.start(); QTextDocument doc; QTextDocument shadowDoc; if (Qt::mightBeRichText(html())) { doc.setHtml(html()); shadowDoc.setHtml(html()); } else { doc.setPlainText(html()); shadowDoc.setPlainText(html()); } int textWidth = m_textWidth; doc.setTextWidth(textWidth); shadowDoc.setTextWidth(textWidth); // Apply outline pen to the html QTextCursor cursor(&doc); cursor.select(QTextCursor::Document); QTextCharFormat format; QPen p(Qt::NoPen); if(outlineEnabled()) { p = outlinePen(); p.setJoinStyle(Qt::MiterJoin); } format.setTextOutline(p); //format.setForeground(fillEnabled() ? fillBrush() : Qt::NoBrush); //Qt::white); cursor.mergeCharFormat(format); // Setup the shadow text formatting if enabled if(shadowEnabled()) { if(shadowBlurRadius() <= 0.05) { QTextCursor cursor(&shadowDoc); cursor.select(QTextCursor::Document); QTextCharFormat format; format.setTextOutline(Qt::NoPen); format.setForeground(shadowBrush()); cursor.mergeCharFormat(format); } } QSizeF shadowSize = shadowEnabled() ? QSizeF(shadowOffsetX(),shadowOffsetY()) : QSizeF(0,0); QSizeF docSize = doc.size(); QSizeF padSize(12.,12.); QSizeF sumSize = (docSize + shadowSize + padSize);//.toSize(); QSizeF scaledSize = QSizeF(sumSize.width() * m_scaling.x(), sumSize.height() * m_scaling.y()); if(m_scaling.x() != 1. || m_scaling.y() != 1.) { //qDebug() << "RichTextRenderer::renderText(): Orig size:"<<sumSize<<", scaled size:"<<scaledSize<<", scaling:"<<m_scaling; m_rawSize = sumSize; } //qDebug() << "RichTextRenderer::update(): textWidth: "<<textWidth<<", shadowSize:"<<shadowSize<<", docSize:"<<docSize<<", sumSize:"<<sumSize; QImage cache(scaledSize.toSize(),QImage::Format_ARGB32); //_Premultiplied); memset(cache.scanLine(0),0,cache.byteCount()); double padSizeHalfX = padSize.width() / 2; double padSizeHalfY = padSize.height() / 2; QPainter textPainter(&cache); textPainter.scale(m_scaling.x(), m_scaling.y()); //textPainter.fillRect(cache.rect(),Qt::transparent); QAbstractTextDocumentLayout::PaintContext pCtx; //qDebug() << "RichTextRenderer::renderText(): shadowEnabled():"<<shadowEnabled()<<", shadowBlurRadius():"<<shadowBlurRadius(); if(shadowEnabled()) { if(shadowBlurRadius() <= 0.05) { // render a "cheap" version of the shadow using the shadow text document textPainter.save(); textPainter.translate(shadowOffsetX(),shadowOffsetY()); shadowDoc.documentLayout()->draw(&textPainter, pCtx); textPainter.restore(); } else { double radius = shadowBlurRadius(); // create temporary pixmap to hold a copy of the text QSizeF blurSize = ImageFilters::blurredSizeFor(doc.size(), (int)radius); QSizeF scaledBlurSize = QSize(blurSize.width() * m_scaling.x(), blurSize.height() * m_scaling.y()); //QSize docSize = doc.size(); //qDebug() << "RichTextRenderer::renderText(): [shadow] radius:"<<radius<<" blurSize:"<<blurSize<<", scaling:"<<m_scaling<<", scaledBlurSize:"<<scaledBlurSize; //qDebug() << "Blur size:"<<blurSize<<", doc:"<<doc.size()<<", radius:"<<radius; QImage tmpImage(scaledBlurSize.toSize(),QImage::Format_ARGB32_Premultiplied); memset(tmpImage.scanLine(0),0,tmpImage.byteCount()); // render the text QPainter tmpPainter(&tmpImage); tmpPainter.scale(m_scaling.x(), m_scaling.y()); tmpPainter.save(); tmpPainter.translate(radius + padSizeHalfX, radius + padSizeHalfY); doc.documentLayout()->draw(&tmpPainter, pCtx); tmpPainter.restore(); // blacken the text by applying a color to the copy using a QPainter::CompositionMode_DestinationIn operation. // This produces a homogeneously-colored pixmap. QRect rect = tmpImage.rect(); tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn); tmpPainter.fillRect(rect, shadowBrush().color()); tmpPainter.end(); // blur the colored text ImageFilters::blurImage(tmpImage, (int)radius); // render the blurred text at an offset into the cache textPainter.save(); textPainter.translate(shadowOffsetX() - radius, shadowOffsetY() - radius); textPainter.drawImage(0, 0, tmpImage); textPainter.restore(); } } textPainter.translate(padSizeHalfX, padSizeHalfY); doc.documentLayout()->draw(&textPainter, pCtx); textPainter.end(); m_image = cache.convertToFormat(QImage::Format_ARGB32); emit textRendered(m_image); //qDebug() << "RichTextRenderer::renderText(): Render finished, elapsed:"<<renderTime.elapsed()<<"ms"; //m_image.save("debug-text.png"); return m_image; }
void TextBoxContent::paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget) { DEBUG_TSTART(); // paint parent AbstractContent::paint(painter, option, widget); painter->save(); //TODO should we clip to the rect or FORCE resize the rect? probably clip... //painter->setClipRect(contentsRect()); //if(option) // painter->setClipRect(option->exposedRect); painter->translate(contentsRect().topLeft()); // + QPoint(p.width(),p.width())); if(sceneContextHint() == MyGraphicsScene::StaticPreview || !modelItem()->shadowEnabled()) { // If we're drawing in a Preview scene, then we render directly with the painter // (rather than caching the results in a pixmap) because this allows the painter // to scale the text glyphs directly (vector scaling), rather than scaling bits // in a pixmap (bitmap scaling), producing more legible results at lower scalings // qDebug() << modelItem()->itemName()<<"TextBoxContent::paint: Rendering either preview or no shadow"; QAbstractTextDocumentLayout::PaintContext pCtx; // What was this for - improving performance? // I've removed it because it seems to be causing the issue reported in Issue #51 on the google code issues tracker. // I'll keep an eye on performance to see if it suffers at all. For now, closing issue #51. //pCtx.clip = option->exposedRect; bool needRestore = false; if(m_zoomEnabled && sceneContextHint() == MyGraphicsScene::Live) { needRestore = true; painter->save(); double xf = (1/m_zoomDestPoint.x()); double yf = (1/m_zoomDestPoint.y()); double sx = m_zoomCurSize.x() / m_zoomStartSize.x(); double sy = m_zoomCurSize.y() / m_zoomStartSize.y(); QRect cRect = contentsRect(); painter->translate(cRect.width()/xf - m_zoomCurSize.x()/xf,cRect.height()/yf - m_zoomCurSize.y()/yf); painter->scale(sx,sy); // qDebug() << modelItem()->itemName()<<"TextBoxContent::paint: Enabling tranlate & scale. Scale:"<<sx<<","<<sy<<". xf/yf:"<<xf<<","<<yf; } if(modelItem()->shadowEnabled()) { // qDebug() << modelItem()->itemName()<<"TextBoxContent::paint: Drawing m_shadowText"; painter->save(); painter->translate(modelItem()->shadowOffsetX(),modelItem()->shadowOffsetY()); m_shadowText->documentLayout()->draw(painter, pCtx); painter->restore(); } m_text->documentLayout()->draw(painter, pCtx); if(needRestore) painter->restore(); } else { QPixmap cache; // qDebug() << modelItem()->itemName()<<"TextBoxContent::paint: Rendering either live or with shadow"; // The primary and only reason we cache the text rendering is inorder // to paint the text and shadow as a single unit (e.g. composite the // shadow+text BEFORE applying opacity rather than setting the opacity // before rendering the shaodw.) If we didnt cache the text as a pixmap // (e.g. render text directly) then when crossfading, the shadow // "apperas" to fade out last, after the text. // Update 20091015: Implemented very aggressive caching across TextBoxContent instances // that share the same modelItem() (see ::cacheKey()) inorder to avoid re-rendering // potentially expensive drop shadows, below. QString key = cacheKey(); if(m_text->toPlainText().trimmed().isEmpty()) { // "<< m_text->toHtml()<<" //qDebug() << modelItem()->itemName()<<": Not rendering cache because:"<< QPixmapCache::find(key,cache)<< " or ...";//plain "<<m_text->toPlainText()<<" is empty"; cache = QPixmap(contentsRect().size()); cache.fill(Qt::transparent); } else { if(!QPixmapCache::find(key,cache)) { if(QFile(key).exists()) { cache.load(key); QPixmapCache::insert(key,cache); //qDebug()<<"TextBoxContent::paint(): modelItem:"<<modelItem()->itemName()<<": Cache load from"<<key; } else { qDebug()<<"TextBoxContent::paint(): modelItem:"<<modelItem()->itemName()<<": Cache redraw"; QSizeF shadowSize = modelItem()->shadowEnabled() ? QSizeF(modelItem()->shadowOffsetX(),modelItem()->shadowOffsetY()) : QSizeF(0,0); cache = QPixmap((contentsRect().size()+shadowSize).toSize()); cache.fill(Qt::transparent); QPainter textPainter(&cache); QAbstractTextDocumentLayout::PaintContext pCtx; #if QT46_SHADOW_ENAB == 0 if(modelItem()->shadowEnabled()) renderShadow(&textPainter,&pCtx); #endif // If we're zooming, we want to render the text straight to the painter // so it can transform the raw vectors instead of scaling the bitmap. // But if we're not zooming, we cache the text with the shadow since it // looks better that way when we're crossfading. if(!m_zoomEnabled) m_text->documentLayout()->draw(&textPainter, pCtx); cache.save(key,"PNG"); QPixmapCache::insert(key, cache); } } } // Draw a rectangular outline in the editor inorder to visually locate empty text blocks if(sceneContextHint() == MyGraphicsScene::Editor && m_text->toPlainText().trimmed() == "") { QPen p = modelItem() ? modelItem()->outlinePen() : QPen(Qt::black,1.5); painter->setPen(p); painter->setBrush(Qt::NoBrush); painter->drawRect(QRect(QPoint(0,0),contentsRect().size())); } else { if(m_zoomEnabled) { double xf = (1/m_zoomDestPoint.x()); double yf = (1/m_zoomDestPoint.y()); double sx = m_zoomCurSize.x() / m_zoomStartSize.x(); double sy = m_zoomCurSize.y() / m_zoomStartSize.y(); painter->save(); QRect cRect = contentsRect(); painter->translate(cRect.width()/xf - m_zoomCurSize.x()/xf,cRect.height()/yf - m_zoomCurSize.y()/yf); painter->scale(sx,sy); painter->drawPixmap(0,0,cache); QAbstractTextDocumentLayout::PaintContext pCtx; m_text->documentLayout()->draw(painter, pCtx); painter->restore(); } else { painter->drawPixmap(0,0,cache); if(sceneContextHint() != MyGraphicsScene::Live && modelItem()->zoomEffectEnabled()) { // cache may not contain the actual text, just shadow, since its not live, // so render the text QAbstractTextDocumentLayout::PaintContext pCtx; m_text->documentLayout()->draw(painter, pCtx); } } } } painter->restore(); //qDebug() << "TextBoxContent::paint(): \t \t Elapsed:"<<(((double)total.elapsed())/1000.0)<<" sec"; }
void TextBoxWarmingThread::run() { if(!m_model) { qDebug()<<"TextBoxWarmingThread::run(): m_model is null"; return; } //qDebug()<<"TextBoxWarmingThread::run(): model ptr:"<<m_model<<", attempting to dynamic cast"; TextBoxItem * model = dynamic_cast<TextBoxItem*>((AbstractVisualItem*)m_model); //int sleepTime = (int)(((float)qrand()) / ((float)RAND_MAX) * 10000.0 + 2000.0); //qDebug()<<"TextBoxWarmingThread::run(): modelItem:"<<model->itemName();//<<": Cache redraw, sleep: "<<sleepTime; // Sleep doesnt work - if I sleep, then it seems the cache is never updated! //sleep((unsigned long)sleepTime); //sleep(1000); QString htmlCode = model->text(); // qDebug()<<model->itemName()<<"TextBoxWarmingThread::run(): htmlCode:"<<htmlCode; QTextDocument doc; QTextDocument shadowDoc; doc.setHtml(htmlCode); shadowDoc.setHtml(htmlCode); int textWidth = model->contentsRect().toRect().width(); doc.setTextWidth(textWidth); shadowDoc.setTextWidth(textWidth); // Apply outline pen to the html QTextCursor cursor(&doc); cursor.select(QTextCursor::Document); QTextCharFormat format; QPen p(Qt::NoPen); if(model && model->outlineEnabled()) { p = model->outlinePen(); p.setJoinStyle(Qt::MiterJoin); } format.setTextOutline(p); format.setForeground(model && model->fillType() == AbstractVisualItem::Solid ? model->fillBrush() : Qt::NoBrush); //Qt::white); cursor.mergeCharFormat(format); #if QT46_SHADOW_ENAB == 0 // Setup the shadow text formatting if enabled if(model && model->shadowEnabled()) { if(qFuzzyIsNull(model->shadowBlurRadius())) { QTextCursor cursor(&shadowDoc); cursor.select(QTextCursor::Document); QTextCharFormat format; format.setTextOutline(Qt::NoPen); format.setForeground(model ? model->shadowBrush() : Qt::black); cursor.mergeCharFormat(format); } } #endif QSizeF shadowSize = model->shadowEnabled() ? QSizeF(model->shadowOffsetX(),model->shadowOffsetY()) : QSizeF(0,0); QImage *cache = new QImage((model->contentsRect().size()+shadowSize).toSize(),QImage::Format_ARGB32_Premultiplied); memset(cache->scanLine(0),0,cache->byteCount()); QPainter textPainter(cache); textPainter.fillRect(cache->rect(),Qt::transparent); QAbstractTextDocumentLayout::PaintContext pCtx; #if QT46_SHADOW_ENAB == 0 if(model->shadowEnabled()) { if(qFuzzyIsNull(model->shadowBlurRadius())) { // render a "cheap" version of the shadow using the shadow text document textPainter.save(); textPainter.translate(model->shadowOffsetX(),model->shadowOffsetY()); shadowDoc.documentLayout()->draw(&textPainter, pCtx); textPainter.restore(); } else { // double radius = model->shadowBlurRadius(); // double radiusSquared = radius*radius; // // // create temporary pixmap to hold a copy of the text // double blurSize = (int)(radiusSquared*2); // QSize shadowSize(blurSize,blurSize); // QImage tmpImage((model->contentsRect().size()+shadowSize).toSize(),QImage::Format_ARGB32); // memset(tmpImage.scanLine(0),0,tmpImage.byteCount()); // // // render the text // QPainter tmpPainter(&tmpImage); // tmpPainter.fillRect(tmpImage.rect(),Qt::transparent); // // tmpPainter.save(); // tmpPainter.translate(radiusSquared, radiusSquared); // doc.documentLayout()->draw(&tmpPainter, pCtx); // tmpPainter.restore(); // // // blacken the text by applying a color to the copy using a QPainter::CompositionMode_DestinationIn operation. // // This produces a homogeneously-colored pixmap. // QRect rect = tmpImage.rect(); // tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn); // tmpPainter.fillRect(rect, model->shadowBrush().color()); // tmpPainter.end(); // // // blur the colored text // QImage blurredImage = ImageFilters::blurred(tmpImage, rect, (int)radius); // // // render the blurred text at an offset into the cache // textPainter.save(); // textPainter.translate(model->shadowOffsetX() - radiusSquared, // model->shadowOffsetY() - radiusSquared); // textPainter.drawImage(0, 0, blurredImage.copy(blurredImage.rect())); // textPainter.restore(); // New method of rendering shadows double radius = model->shadowBlurRadius(); // create temporary pixmap to hold a copy of the text QSizeF blurSize = ImageFilters::blurredSizeFor(model->contentsRect().size(), (int)radius); //qDebug() << "Blur size:"<<blurSize<<", doc:"<<doc.size()<<", radius:"<<radius; QImage tmpImage(blurSize.toSize(),QImage::Format_ARGB32_Premultiplied); memset(tmpImage.scanLine(0),0,tmpImage.byteCount()); // render the text QPainter tmpPainter(&tmpImage); tmpPainter.save(); tmpPainter.translate(radius, radius); doc.documentLayout()->draw(&tmpPainter, pCtx); tmpPainter.restore(); // blacken the text by applying a color to the copy using a QPainter::CompositionMode_DestinationIn operation. // This produces a homogeneously-colored pixmap. QRect rect = tmpImage.rect(); tmpPainter.setCompositionMode(QPainter::CompositionMode_SourceIn); tmpPainter.fillRect(rect, model->shadowBrush().color()); tmpPainter.end(); // blur the colored text ImageFilters::blurImage(tmpImage, (int)radius); // render the blurred text at an offset into the cache textPainter.save(); textPainter.translate(model->shadowOffsetX() - radius, model->shadowOffsetY() - radius); textPainter.drawImage(0, 0, tmpImage); textPainter.restore(); } } #endif doc.documentLayout()->draw(&textPainter, pCtx); textPainter.end(); emit renderDone(cache); }