diff --git a/scribus/pageitem.cpp b/scribus/pageitem.cpp index af8d4fdd53..8a60740919 100644 --- a/scribus/pageitem.cpp +++ b/scribus/pageitem.cpp @@ -2204,6 +2204,17 @@ void PageItem::DrawSoftShadow(ScPainter *p) tmp = defect.convertDefect(tmp, m_Doc->previewVisual); } p->save(); + // Clip to item bounds + shadow offset + blur radius, so beginLayer() + // creates a small surface instead of one sized to the whole viewport. + double blurMargin = (m_softShadowBlurRadius * sc) + + qMax(fabs(m_softShadowXOffset), fabs(m_softShadowYOffset)) * sc + + 2; + QPainterPath clp; + clp.addRect(-blurMargin, -blurMargin, m_width + 2 * blurMargin, m_height + 2 * blurMargin); + FPointArray clpArr; + clpArr.fromQPainterPath(clp); + p->setupPolygon(&clpArr); + p->setClipPath(); if (m_softShadowHasObjectTransparency) p->beginLayer(1.0 - fillTransparency(), m_softShadowBlendMode); else diff --git a/scribus/scpainter.cpp b/scribus/scpainter.cpp index b8828ca6fa..c965dc5d98 100644 --- a/scribus/scpainter.cpp +++ b/scribus/scpainter.cpp @@ -46,6 +46,14 @@ ScPainter::~ScPainter() { cairo_surface_destroy(cairo_get_target(m_cr)); cairo_destroy(m_cr); + delete [] m_blurBufR; + delete [] m_blurBufG; + delete [] m_blurBufB; + delete [] m_blurBufA; + delete [] m_blurVmin; + delete [] m_blurDv; + delete [] m_blurStackData; + delete [] m_blurStack; } void ScPainter::beginLayer(double transparency, int blendmode, FPointArray *clipArray) @@ -2001,25 +2009,65 @@ void ScPainter::blur(int radius) int hm = h - 1; int wh = w * h; int div = radius + radius + 1; - int *r = new int[wh]; - int *g = new int[wh]; - int *b = new int[wh]; - int *a = new int[wh]; + + if (m_blurBufCapacity < (size_t) wh) + { + delete [] m_blurBufR; + delete [] m_blurBufG; + delete [] m_blurBufB; + delete [] m_blurBufA; + m_blurBufR = new int[wh]; + m_blurBufG = new int[wh]; + m_blurBufB = new int[wh]; + m_blurBufA = new int[wh]; + m_blurBufCapacity = wh; + } + int *r = m_blurBufR; + int *g = m_blurBufG; + int *b = m_blurBufB; + int *a = m_blurBufA; + int rsum, gsum, bsum, asum, x, y, i, yp, yi, yw; QRgb p; - int *vmin = new int[qMax(w, h)]; + + size_t vminNeeded = (size_t) qMax(w, h); + if (m_blurVminCapacity < vminNeeded) + { + delete [] m_blurVmin; + m_blurVmin = new int[vminNeeded]; + m_blurVminCapacity = vminNeeded; + } + int *vmin = m_blurVmin; + int divsum = (div+1)>>1; divsum *= divsum; - int *dv = new int[256 * (size_t) divsum]; + size_t dvNeeded = 256 * (size_t) divsum; + if (m_blurDvCapacity < dvNeeded) + { + delete [] m_blurDv; + m_blurDv = new int[dvNeeded]; + m_blurDvCapacity = dvNeeded; + } + int *dv = m_blurDv; for (i = 0; i < 256 * divsum; ++i) { dv[i] = (i / divsum); } + yw = yi = 0; - int **stack = new int*[div]; + if (m_blurStackCapacity < (size_t) div) + { + delete [] m_blurStack; + delete [] m_blurStackData; + m_blurStack = new int*[div]; + m_blurStackData = new int[div * 4]; + m_blurStackCapacity = div; + } + int **stack = m_blurStack; + int *stackData = m_blurStackData; for (int i = 0; i < div; ++i) { - stack[i] = new int[4]; + stack[i] = stackData + (i * 4); } int stackpointer; int stackstart; @@ -2188,16 +2236,5 @@ void ScPainter::blur(int radius) yi += w; } } - delete [] r; - delete [] g; - delete [] b; - delete [] a; - delete [] vmin; - delete [] dv; - for (int i = 0; i < div; ++i) - { - delete [] stack[i]; - } - delete [] stack; cairo_surface_mark_dirty(data); } diff --git a/scribus/scpainter.h b/scribus/scpainter.h index de9822680b..2be4faa76a 100644 --- a/scribus/scpainter.h +++ b/scribus/scpainter.h @@ -146,6 +146,24 @@ private: void fillPathHelper(); void strokePathHelper(); + // Scratch buffers reused across blur() calls to avoid new/delete churn. + // Grown on demand, never shrunk, freed in the destructor. + int *m_blurBufR { nullptr }; + int *m_blurBufG { nullptr }; + int *m_blurBufB { nullptr }; + int *m_blurBufA { nullptr }; + size_t m_blurBufCapacity { 0 }; // capacity in pixels (w*h) for r/g/b/a + + int *m_blurVmin { nullptr }; + size_t m_blurVminCapacity { 0 }; // capacity = max(w,h) + + int *m_blurDv { nullptr }; + size_t m_blurDvCapacity { 0 }; // capacity = 256*divsum + + int *m_blurStackData { nullptr }; + int **m_blurStack { nullptr }; + size_t m_blurStackCapacity { 0 }; // capacity = div (radius*2+1) + cairo_t* m_cr { nullptr }; struct layerProp {