diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2021-12-28 14:21:03 +0900 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2022-01-04 15:16:30 +0100 |
commit | eee703970581545b56f3b2faa5b5911923ec28ea (patch) | |
tree | ec2b4c5ae87a6afe32ffda265af7368688abf2b2 /vcl | |
parent | 3e9786b4dcbf342aab469940710e8a01be62d694 (diff) |
vcl: move SurfaceHelper class to CairoCommon
Intermediate step beore moving bitmap related members.
Change-Id: Icf2d4cfb787dfb029f299cba4b4ffabae563bf6d
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127923
Tested-by: Jenkins
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/headless/CairoCommon.cxx | 124 | ||||
-rw-r--r-- | vcl/headless/svpgdi.cxx | 136 | ||||
-rw-r--r-- | vcl/inc/headless/CairoCommon.hxx | 27 |
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: */ |