From a2e8238045820cb3d74aae9564e2efdba205a3eb Mon Sep 17 00:00:00 2001 From: Charles Yin Date: Tue, 13 Sep 2011 13:53:25 +1000 Subject: [PATCH] fix broken canvas blur after merging refactor branch Change-Id: If145f1d02566f839abeb50df167db2b237499290 Reviewed-on: http://codereview.qt-project.org/4857 Reviewed-by: Qt Sanity Bot Reviewed-by: Charles Yin --- .../canvas/twitterfriends/TwitterUser.qml | 4 +- src/declarative/items/context2d/qsgcontext2d.cpp | 194 ++++++++------------ .../items/context2d/qsgcontext2dcommandbuffer.cpp | 20 +-- .../items/context2d/qsgcontext2dcommandbuffer_p.h | 5 - 4 files changed, 84 insertions(+), 139 deletions(-) diff --git a/examples/declarative/canvas/twitterfriends/TwitterUser.qml b/examples/declarative/canvas/twitterfriends/TwitterUser.qml index 4e6bb9e..7b16581 100644 --- a/examples/declarative/canvas/twitterfriends/TwitterUser.qml +++ b/examples/declarative/canvas/twitterfriends/TwitterUser.qml @@ -131,13 +131,13 @@ Item { twitterUser.showFriends(ctx); ctx.shadowOffsetX = 5; ctx.shadowOffsetY = 5; - ctx.shadowBlur = 20; + ctx.shadowBlur = 7; ctx.shadowColor = "blue"; ctx.globalAlpha = 1; } else { ctx.shadowOffsetX = 5; ctx.shadowOffsetY = 5; - ctx.shadowBlur = 20; + ctx.shadowBlur = 7; ctx.shadowColor = twitterUser.linkColor; ctx.globalAlpha = 0.6; } diff --git a/src/declarative/items/context2d/qsgcontext2d.cpp b/src/declarative/items/context2d/qsgcontext2d.cpp index af2676f..6762c91 100644 --- a/src/declarative/items/context2d/qsgcontext2d.cpp +++ b/src/declarative/items/context2d/qsgcontext2d.cpp @@ -338,45 +338,52 @@ public: QImage image; }; -static QImage qt_texture_to_image(QSGTexture* texture) -{ - if (!texture || !texture->textureId()) - return QImage(); - QOpenGLFramebufferObjectFormat format; - format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); - format.setInternalTextureFormat(GL_RGBA); - format.setMipmap(false); - QOpenGLFramebufferObject* fbo = new QOpenGLFramebufferObject(texture->textureSize(), format); -#if 0 - // ### refactor - fbo->drawTexture(QPointF(0,0), texture->textureId(), GL_TEXTURE_2D); -#endif - return fbo->toImage(); -} - -static QSGTexture* qt_item_to_texture(QSGItem* item) -{ - if (!item) - return 0; - QSGShaderEffectTexture* texture = new QSGShaderEffectTexture(item); - texture->setItem(QSGItemPrivate::get(item)->itemNode()); - texture->setLive(true); - - QRectF sourceRect = QRectF(0, 0, item->width(), item->height()); - - texture->setRect(sourceRect); - QSize textureSize = QSize(qCeil(qAbs(sourceRect.width())), qCeil(qAbs(sourceRect.height()))); - texture->setSize(textureSize); - texture->setRecursive(false); - texture->setFormat(GL_RGBA); - texture->setHasMipmaps(false); - texture->markDirtyTexture(); - texture->updateTexture(); - return texture; -} - -static QImage qt_item_to_image(QSGItem* item) { - return qt_texture_to_image(qt_item_to_texture(item)); +QImage qt_image_convolute_filter(const QImage& src, const QVector& weights, int radius = 0) +{ + int sides = radius ? radius : qRound(qSqrt(weights.size())); + int half = qFloor(sides/2); + + QImage dst = QImage(src.size(), src.format()); + int w = src.width(); + int h = src.height(); + for (int y = 0; y < dst.height(); ++y) { + QRgb *dr = (QRgb*)dst.scanLine(y); + for (int x = 0; x < dst.width(); ++x) { + unsigned char* dRgb = ((unsigned char*)&dr[x]); + unsigned char red=0, green=0, blue=0, alpha=0; + int sy = y; + int sx = x; + + for (int cy=0; cy= 0 && scy < w && scx >= 0 && scx < h) { + const QRgb *sr = (const QRgb*)(src.constScanLine(scy)); + const unsigned char* sRgb = ((const unsigned char*)&sr[scx]); + qreal wt = radius ? weights[0] : weights[cy*sides+cx]; + red += sRgb[0] * wt; + green += sRgb[1] * wt; + blue += sRgb[2] * wt; + alpha += sRgb[3] * wt; + } + } + } + dRgb[0] = red; + dRgb[1] = green; + dRgb[2] = blue; + dRgb[3] = alpha; + } + } + return dst; +} + +void qt_image_boxblur(QImage& image, int radius, bool quality) +{ + int passes = quality? 3: 1; + for (int i=0; i < passes; i++) { + image = qt_image_convolute_filter(image, QVector() << 1.0/(radius * radius * 1.0), radius); + } } static QPainter::CompositionMode qt_composite_mode_from_string(const QString &compositeOperator) @@ -1010,24 +1017,24 @@ static v8::Handle ctx2d_createPattern(const v8::Arguments &args) QV8Engine *engine = V8ENGINE(); - if (args.Length() == 2) { - QSGContext2DEngineData *ed = engineData(engine); - v8::Local pattern = ed->constructorPattern->NewInstance(); - QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine); +// if (args.Length() == 2) { +// QSGContext2DEngineData *ed = engineData(engine); +// v8::Local pattern = ed->constructorPattern->NewInstance(); +// QV8Context2DStyleResource *r = new QV8Context2DStyleResource(engine); - QImage img; +// QImage img; - QSGItem* item = qobject_cast(engine->toQObject(args[0])); - if (item) { - img = qt_item_to_image(item); +// QSGItem* item = qobject_cast(engine->toQObject(args[0])); +// if (item) { +// img = qt_item_to_image(item); // if (img.isNull()) { // //exception: INVALID_STATE_ERR // } - } /*else { - //exception: TYPE_MISMATCH_ERR - }*/ +// } /*else { +// //exception: TYPE_MISMATCH_ERR +// }*/ - QString repetition = engine->toString(args[1]); +// QString repetition = engine->toString(args[1]); // if (repetition == "repeat" || repetition.isEmpty()) { // //TODO @@ -1040,10 +1047,10 @@ static v8::Handle ctx2d_createPattern(const v8::Arguments &args) // } else { // //TODO: exception: SYNTAX_ERR // } - r->brush = img; - pattern->SetExternalResource(r); - return pattern; - } +// r->brush = img; +// pattern->SetExternalResource(r); + // return pattern; +// } return v8::Null(); } @@ -1558,7 +1565,7 @@ static v8::Handle ctx2d_closePath(const v8::Arguments &args) static v8::Handle ctx2d_fill(const v8::Arguments &args) { QV8Context2DResource *r = v8_resource_cast(args.This()); - CHECK_CONTEXT(r) + CHECK_CONTEXT(r); r->context->buffer()->fill(r->context->m_path); @@ -1687,7 +1694,7 @@ static v8::Handle ctx2d_ellipse(const v8::Arguments &args) CHECK_CONTEXT(r) - if (args.Length() == 6) { + if (args.Length() == 4) { r->context->ellipse(args[0]->NumberValue(), args[1]->NumberValue(), args[2]->NumberValue(), @@ -2170,19 +2177,6 @@ static v8::Handle ctx2d_imageData_mirror(const v8::Arguments &args) horizontal = args[0]->BooleanValue(); vertical = args[1]->BooleanValue(); } -#if 0 - // ### refactor - // blur the alpha channel - if (state.shadowBlur > 0) { - QImage blurred(shadowImg.size(), QImage::Format_ARGB32); - blurred.fill(0); - QPainter blurPainter(&blurred); - qt_blurImage(&blurPainter, shadowImg, state.shadowBlur, false, true); - blurPainter.end(); - shadowImg = blurred; - } -#endif - r->image = r->image.mirrored(horizontal, vertical); return args.This(); } @@ -2250,18 +2244,15 @@ static v8::Handle ctx2d_imageData_filter(const v8::Arguments &args) break; case QSGCanvasItem::Blur : { - QImage blurred(r->image.size(), QImage::Format_ARGB32); - qreal blur = 10; + int radius = 3; + bool quality = false; + if (args.Length() > 1) - blur = args[1]->NumberValue(); - - blurred.fill(Qt::transparent); - QPainter blurPainter(&blurred); -#if 0 - qt_blurImage(&blurPainter, r->image, blur, true, false); -#endif - blurPainter.end(); - r->image = blurred; + radius = args[1]->IntegerValue() / 2; + if (args.Length() > 2) + quality = args[2]->BooleanValue(); + + qt_image_boxblur(r->image, radius, quality); } break; case QSGCanvasItem::Opaque : @@ -2278,45 +2269,10 @@ static v8::Handle ctx2d_imageData_filter(const v8::Arguments &args) { if (args.Length() > 1 && args[1]->IsArray()) { v8::Local array = v8::Local::Cast(args[1]); - QVector weights; + QVector weights; for (uint32_t i = 0; i < array->Length(); ++i) weights.append(array->Get(i)->NumberValue()); - int sides = qRound(qSqrt(weights.size())); - int half = qFloor(sides/2); - - QImage image = QImage(r->image.size(), QImage::Format_ARGB32); - int w = r->image.width(); - int h = r->image.height(); - for (int y = 0; y < image.height(); ++y) { - QRgb *dRow = (QRgb*)image.scanLine(y); - for (int x = 0; x < image.width(); ++x) { - unsigned char* dRgb = ((unsigned char*)&dRow[x]); - unsigned char red=0, green=0, blue=0, alpha=0; - int sy = y; - int sx = x; - - for (int cy=0; cy= 0 && scy < w && scx >= 0 && scx < h) { - QRgb *sRow = (QRgb*)(r->image.scanLine(scy)); - unsigned char* sRgb = ((unsigned char*)&sRow[scx]); - int wt = weights[cy*sides+cx]; - red += sRgb[0] * wt; - green += sRgb[1] * wt; - blue += sRgb[2] * wt; - alpha += sRgb[3] * wt; - } - } - } - dRgb[0] = red; - dRgb[1] = green; - dRgb[2] = blue; - dRgb[3] = alpha; - } - } - r->image = image; + r->image = qt_image_convolute_filter(r->image, weights); } else { //error } @@ -2932,7 +2888,7 @@ QSGContext2DEngineData::QSGContext2DEngineData(QV8Engine *engine) ft->PrototypeTemplate()->Set(v8::String::New("moveTo"), V8FUNCTION(ctx2d_moveTo, engine)); ft->PrototypeTemplate()->Set(v8::String::New("quadraticCurveTo"), V8FUNCTION(ctx2d_quadraticCurveTo, engine)); ft->PrototypeTemplate()->Set(v8::String::New("rect"), V8FUNCTION(ctx2d_rect, engine)); - ft->PrototypeTemplate()->Set(v8::String::New("roundedRect "), V8FUNCTION(ctx2d_roundedRect, engine)); + ft->PrototypeTemplate()->Set(v8::String::New("roundedRect"), V8FUNCTION(ctx2d_roundedRect, engine)); ft->PrototypeTemplate()->Set(v8::String::New("text"), V8FUNCTION(ctx2d_text, engine)); ft->PrototypeTemplate()->Set(v8::String::New("ellipse"), V8FUNCTION(ctx2d_ellipse, engine)); ft->PrototypeTemplate()->Set(v8::String::New("stroke"), V8FUNCTION(ctx2d_stroke, engine)); diff --git a/src/declarative/items/context2d/qsgcontext2dcommandbuffer.cpp b/src/declarative/items/context2d/qsgcontext2dcommandbuffer.cpp index 0448fa0..224f640 100644 --- a/src/declarative/items/context2d/qsgcontext2dcommandbuffer.cpp +++ b/src/declarative/items/context2d/qsgcontext2dcommandbuffer.cpp @@ -45,10 +45,13 @@ #include #define HAS_SHADOW(offsetX, offsetY, blur, color) (color.isValid() && color.alpha() && (blur || offsetX || offsetY)) + +void qt_image_boxblur(QImage& image, int radius, bool quality); + static QImage makeShadowImage(const QImage& image, qreal offsetX, qreal offsetY, qreal blur, const QColor& color) { - QImage shadowImg(image.width() + blur * 2 + qAbs(offsetX), - image.height() + blur *2 + qAbs(offsetY), + QImage shadowImg(image.width() + blur + qAbs(offsetX), + image.height() + blur + qAbs(offsetY), QImage::Format_ARGB32); shadowImg.fill(0); QPainter tmpPainter(&shadowImg); @@ -59,17 +62,8 @@ static QImage makeShadowImage(const QImage& image, qreal offsetX, qreal offsetY, tmpPainter.drawImage(shadowX, shadowY, image); tmpPainter.end(); - // blur the alpha channel - if (blur > 0) { - QImage blurred(shadowImg.size(), QImage::Format_ARGB32); - blurred.fill(0); - QPainter blurPainter(&blurred); -#if 0 - qt_blurImage(&blurPainter, shadowImg, blur, true, false); -#endif - blurPainter.end(); - shadowImg = blurred; - } + if (blur > 0) + qt_image_boxblur(shadowImg, blur/2, true); // blacken the image with shadow color... tmpPainter.begin(&shadowImg); diff --git a/src/declarative/items/context2d/qsgcontext2dcommandbuffer_p.h b/src/declarative/items/context2d/qsgcontext2dcommandbuffer_p.h index d238027..d95adee 100644 --- a/src/declarative/items/context2d/qsgcontext2dcommandbuffer_p.h +++ b/src/declarative/items/context2d/qsgcontext2dcommandbuffer_p.h @@ -45,11 +45,6 @@ #include "qsgcontext2d_p.h" #include "qdeclarativepixmapcache_p.h" -// Note, this is exported but in a private header as qtopengl depends on it. -// But it really should be considered private API -void qt_blurImage(QPainter *p, QImage &blurImage, qreal radius, bool quality, bool alphaOnly, int transposed = 0); -void qt_blurImage(QImage &blurImage, qreal radius, bool quality, int transposed = 0); - QT_BEGIN_HEADER -- 1.7.2.5