summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--vcl/headless/CairoCommon.cxx124
-rw-r--r--vcl/headless/svpgdi.cxx136
-rw-r--r--vcl/inc/headless/CairoCommon.hxx27
3 files changed, 151 insertions, 136 deletions
diff --git a/vcl/headless/CairoCommon.cxx b/vcl/headless/CairoCommon.cxx
index 6194d976ab7b..94ca2c3158be 100644
--- a/vcl/headless/CairoCommon.cxx
+++ b/vcl/headless/CairoCommon.cxx
@@ -1173,4 +1173,128 @@ void Toggle1BitTransparency(const BitmapBuffer& rBuf)
}
}
+namespace
+{
+// check for env var that decides for using downscale pattern
+const char* pDisableDownScale(getenv("SAL_DISABLE_CAIRO_DOWNSCALE"));
+bool bDisableDownScale(nullptr != pDisableDownScale);
+}
+
+cairo_surface_t* SurfaceHelper::implCreateOrReuseDownscale(unsigned long nTargetWidth,
+ unsigned long nTargetHeight)
+{
+ const unsigned long nSourceWidth(cairo_image_surface_get_width(pSurface));
+ const unsigned long nSourceHeight(cairo_image_surface_get_height(pSurface));
+
+ // zoomed in, need to stretch at paint, no pre-scale useful
+ if (nTargetWidth >= nSourceWidth || nTargetHeight >= nSourceHeight)
+ {
+ return pSurface;
+ }
+
+ // calculate downscale factor
+ unsigned long nWFactor(1);
+ unsigned long nW((nSourceWidth + 1) / 2);
+ unsigned long nHFactor(1);
+ unsigned long nH((nSourceHeight + 1) / 2);
+
+ while (nW > nTargetWidth && nW > 1)
+ {
+ nW = (nW + 1) / 2;
+ nWFactor *= 2;
+ }
+
+ while (nH > nTargetHeight && nH > 1)
+ {
+ nH = (nH + 1) / 2;
+ nHFactor *= 2;
+ }
+
+ if (1 == nWFactor && 1 == nHFactor)
+ {
+ // original size *is* best binary size, use it
+ return pSurface;
+ }
+
+ // go up one scale again - look for no change
+ nW = (1 == nWFactor) ? nTargetWidth : nW * 2;
+ nH = (1 == nHFactor) ? nTargetHeight : nH * 2;
+
+ // check if we have a downscaled version of required size
+ // bail out if the multiplication for the key would overflow
+ if (nW >= SAL_MAX_UINT32 || nH >= SAL_MAX_UINT32)
+ return pSurface;
+ const sal_uInt64 key((nW * static_cast<sal_uInt64>(SAL_MAX_UINT32)) + nH);
+ auto isHit(maDownscaled.find(key));
+
+ if (isHit != maDownscaled.end())
+ {
+ return isHit->second;
+ }
+
+ // create new surface in the targeted size
+ cairo_surface_t* pSurfaceTarget
+ = cairo_surface_create_similar(pSurface, cairo_surface_get_content(pSurface), nW, nH);
+
+ // made a version to scale self first that worked well, but would've
+ // been hard to support CAIRO_FORMAT_A1 including bit shifting, so
+ // I decided to go with cairo itself - use CAIRO_FILTER_FAST or
+ // CAIRO_FILTER_GOOD though. Please modify as needed for
+ // performance/quality
+ cairo_t* cr = cairo_create(pSurfaceTarget);
+ const double fScaleX(static_cast<double>(nW) / static_cast<double>(nSourceWidth));
+ const double fScaleY(static_cast<double>(nH) / static_cast<double>(nSourceHeight));
+ cairo_scale(cr, fScaleX, fScaleY);
+ cairo_set_source_surface(cr, pSurface, 0.0, 0.0);
+ cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_GOOD);
+ cairo_paint(cr);
+ cairo_destroy(cr);
+
+ // need to set device_scale for downscale surfaces to get
+ // them handled correctly
+ cairo_surface_set_device_scale(pSurfaceTarget, fScaleX, fScaleY);
+
+ // add entry to cached entries
+ maDownscaled[key] = pSurfaceTarget;
+
+ return pSurfaceTarget;
+}
+
+bool SurfaceHelper::isTrivial() const
+{
+ constexpr unsigned long nMinimalSquareSizeToBuffer(64 * 64);
+ const unsigned long nSourceWidth(cairo_image_surface_get_width(pSurface));
+ const unsigned long nSourceHeight(cairo_image_surface_get_height(pSurface));
+
+ return nSourceWidth * nSourceHeight < nMinimalSquareSizeToBuffer;
+}
+
+SurfaceHelper::SurfaceHelper()
+ : pSurface(nullptr)
+{
+}
+
+SurfaceHelper::~SurfaceHelper()
+{
+ cairo_surface_destroy(pSurface);
+ for (auto& candidate : maDownscaled)
+ {
+ cairo_surface_destroy(candidate.second);
+ }
+}
+
+cairo_surface_t* SurfaceHelper::getSurface(unsigned long nTargetWidth,
+ unsigned long nTargetHeight) const
+{
+ if (bDisableDownScale || 0 == nTargetWidth || 0 == nTargetHeight || !pSurface || isTrivial())
+ {
+ // caller asks for original or disabled or trivial (smaller then a minimal square size)
+ // also excludes zero cases for width/height after this point if need to prescale
+ return pSurface;
+ }
+
+ return const_cast<SurfaceHelper*>(this)->implCreateOrReuseDownscale(nTargetWidth,
+ nTargetHeight);
+}
+
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx
index 92c0cbe39fbb..c894ebbcb38f 100644
--- a/vcl/headless/svpgdi.cxx
+++ b/vcl/headless/svpgdi.cxx
@@ -63,142 +63,6 @@ namespace
const char* pDisableDownScale(getenv("SAL_DISABLE_CAIRO_DOWNSCALE"));
bool bDisableDownScale(nullptr != pDisableDownScale);
- class SurfaceHelper
- {
- private:
- cairo_surface_t* pSurface;
- std::unordered_map<sal_uInt64, cairo_surface_t*> maDownscaled;
-
- SurfaceHelper(const SurfaceHelper&) = delete;
- SurfaceHelper& operator=(const SurfaceHelper&) = delete;
-
- cairo_surface_t* implCreateOrReuseDownscale(
- unsigned long nTargetWidth,
- unsigned long nTargetHeight)
- {
- const unsigned long nSourceWidth(cairo_image_surface_get_width(pSurface));
- const unsigned long nSourceHeight(cairo_image_surface_get_height(pSurface));
-
- // zoomed in, need to stretch at paint, no pre-scale useful
- if(nTargetWidth >= nSourceWidth || nTargetHeight >= nSourceHeight)
- {
- return pSurface;
- }
-
- // calculate downscale factor
- unsigned long nWFactor(1);
- unsigned long nW((nSourceWidth + 1) / 2);
- unsigned long nHFactor(1);
- unsigned long nH((nSourceHeight + 1) / 2);
-
- while(nW > nTargetWidth && nW > 1)
- {
- nW = (nW + 1) / 2;
- nWFactor *= 2;
- }
-
- while(nH > nTargetHeight && nH > 1)
- {
- nH = (nH + 1) / 2;
- nHFactor *= 2;
- }
-
- if(1 == nWFactor && 1 == nHFactor)
- {
- // original size *is* best binary size, use it
- return pSurface;
- }
-
- // go up one scale again - look for no change
- nW = (1 == nWFactor) ? nTargetWidth : nW * 2;
- nH = (1 == nHFactor) ? nTargetHeight : nH * 2;
-
- // check if we have a downscaled version of required size
- // bail out if the multiplication for the key would overflow
- if( nW >= SAL_MAX_UINT32 || nH >= SAL_MAX_UINT32 )
- return pSurface;
- const sal_uInt64 key((nW * static_cast<sal_uInt64>(SAL_MAX_UINT32)) + nH);
- auto isHit(maDownscaled.find(key));
-
- if(isHit != maDownscaled.end())
- {
- return isHit->second;
- }
-
- // create new surface in the targeted size
- cairo_surface_t* pSurfaceTarget = cairo_surface_create_similar(
- pSurface,
- cairo_surface_get_content(pSurface),
- nW,
- nH);
-
- // made a version to scale self first that worked well, but would've
- // been hard to support CAIRO_FORMAT_A1 including bit shifting, so
- // I decided to go with cairo itself - use CAIRO_FILTER_FAST or
- // CAIRO_FILTER_GOOD though. Please modify as needed for
- // performance/quality
- cairo_t* cr = cairo_create(pSurfaceTarget);
- const double fScaleX(static_cast<double>(nW)/static_cast<double>(nSourceWidth));
- const double fScaleY(static_cast<double>(nH)/static_cast<double>(nSourceHeight));
- cairo_scale(cr, fScaleX, fScaleY);
- cairo_set_source_surface(cr, pSurface, 0.0, 0.0);
- cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_GOOD);
- cairo_paint(cr);
- cairo_destroy(cr);
-
- // need to set device_scale for downscale surfaces to get
- // them handled correctly
- cairo_surface_set_device_scale(pSurfaceTarget, fScaleX, fScaleY);
-
- // add entry to cached entries
- maDownscaled[key] = pSurfaceTarget;
-
- return pSurfaceTarget;
- }
-
- protected:
- cairo_surface_t* implGetSurface() const { return pSurface; }
- void implSetSurface(cairo_surface_t* pNew) { pSurface = pNew; }
-
- bool isTrivial() const
- {
- constexpr unsigned long nMinimalSquareSizeToBuffer(64*64);
- const unsigned long nSourceWidth(cairo_image_surface_get_width(pSurface));
- const unsigned long nSourceHeight(cairo_image_surface_get_height(pSurface));
-
- return nSourceWidth * nSourceHeight < nMinimalSquareSizeToBuffer;
- }
-
- public:
- explicit SurfaceHelper()
- : pSurface(nullptr)
- {
- }
- ~SurfaceHelper()
- {
- cairo_surface_destroy(pSurface);
- for(auto& candidate : maDownscaled)
- {
- cairo_surface_destroy(candidate.second);
- }
- }
- cairo_surface_t* getSurface(
- unsigned long nTargetWidth = 0,
- unsigned long nTargetHeight = 0) const
- {
- if (bDisableDownScale || 0 == nTargetWidth || 0 == nTargetHeight || !pSurface || isTrivial())
- {
- // caller asks for original or disabled or trivial (smaller then a minimal square size)
- // also excludes zero cases for width/height after this point if need to prescale
- return pSurface;
- }
-
- return const_cast<SurfaceHelper*>(this)->implCreateOrReuseDownscale(
- nTargetWidth,
- nTargetHeight);
- }
- };
-
class BitmapHelper : public SurfaceHelper
{
private:
diff --git a/vcl/inc/headless/CairoCommon.hxx b/vcl/inc/headless/CairoCommon.hxx
index b1f6a8198a60..159714c558d8 100644
--- a/vcl/inc/headless/CairoCommon.hxx
+++ b/vcl/inc/headless/CairoCommon.hxx
@@ -38,6 +38,8 @@
#include <basegfx/polygon/b2dpolypolygon.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
+#include <unordered_map>
+
//Using formats that match cairo's formats. For android we patch cairo,
//which is internal in that case, to swap the rgb components so that
//cairo then matches the OpenGL GL_RGBA format so we can use it there
@@ -199,4 +201,29 @@ struct VCL_DLLPUBLIC CairoCommon
static cairo_surface_t* createCairoSurface(const BitmapBuffer* pBuffer);
};
+class SurfaceHelper
+{
+private:
+ cairo_surface_t* pSurface;
+ std::unordered_map<sal_uInt64, cairo_surface_t*> maDownscaled;
+
+ SurfaceHelper(const SurfaceHelper&) = delete;
+ SurfaceHelper& operator=(const SurfaceHelper&) = delete;
+
+ cairo_surface_t* implCreateOrReuseDownscale(unsigned long nTargetWidth,
+ unsigned long nTargetHeight);
+
+protected:
+ cairo_surface_t* implGetSurface() const { return pSurface; }
+ void implSetSurface(cairo_surface_t* pNew) { pSurface = pNew; }
+
+ bool isTrivial() const;
+
+public:
+ explicit SurfaceHelper();
+ ~SurfaceHelper();
+
+ cairo_surface_t* getSurface(unsigned long nTargetWidth = 0,
+ unsigned long nTargetHeight = 0) const;
+};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */