diff options
Diffstat (limited to 'core/fpdfapi/render')
-rw-r--r-- | core/fpdfapi/render/cpdf_imagecacheentry.cpp (renamed from core/fpdfapi/render/fpdf_render_cache.cpp) | 180 | ||||
-rw-r--r-- | core/fpdfapi/render/cpdf_imagecacheentry.h | 71 | ||||
-rw-r--r-- | core/fpdfapi/render/cpdf_imageloader.cpp | 1 | ||||
-rw-r--r-- | core/fpdfapi/render/cpdf_pagerendercache.cpp | 143 | ||||
-rw-r--r-- | core/fpdfapi/render/cpdf_pagerendercache.h | 30 | ||||
-rw-r--r-- | core/fpdfapi/render/render_int.h | 50 |
6 files changed, 239 insertions, 236 deletions
diff --git a/core/fpdfapi/render/fpdf_render_cache.cpp b/core/fpdfapi/render/cpdf_imagecacheentry.cpp index d30de00edb..93ec162a7c 100644 --- a/core/fpdfapi/render/fpdf_render_cache.cpp +++ b/core/fpdfapi/render/cpdf_imagecacheentry.cpp @@ -1,186 +1,32 @@ -// Copyright 2014 PDFium Authors. All rights reserved. +// Copyright 2016 PDFium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com +#include "core/fpdfapi/render/cpdf_imagecacheentry.h" + #include <memory> #include <utility> #include "core/fpdfapi/page/cpdf_page.h" -#include "core/fpdfapi/page/pageint.h" +#include "core/fpdfapi/parser/cpdf_dictionary.h" #include "core/fpdfapi/parser/cpdf_document.h" +#include "core/fpdfapi/parser/cpdf_stream.h" #include "core/fpdfapi/render/cpdf_pagerendercache.h" #include "core/fpdfapi/render/cpdf_rendercontext.h" #include "core/fpdfapi/render/cpdf_renderstatus.h" #include "core/fpdfapi/render/render_int.h" -struct CACHEINFO { - uint32_t time; - CPDF_Stream* pStream; -}; - -extern "C" { -static int compare(const void* data1, const void* data2) { - return ((CACHEINFO*)data1)->time - ((CACHEINFO*)data2)->time; -} -} // extern "C" - -CPDF_PageRenderCache::CPDF_PageRenderCache(CPDF_Page* pPage) - : m_pPage(pPage), - m_pCurImageCacheEntry(nullptr), - m_nTimeCount(0), - m_nCacheSize(0), - m_bCurFindCache(false) {} - -CPDF_PageRenderCache::~CPDF_PageRenderCache() { - for (const auto& it : m_ImageCache) - delete it.second; -} -void CPDF_PageRenderCache::CacheOptimization(int32_t dwLimitCacheSize) { - if (m_nCacheSize <= (uint32_t)dwLimitCacheSize) - return; - - size_t nCount = m_ImageCache.size(); - CACHEINFO* pCACHEINFO = FX_Alloc(CACHEINFO, nCount); - size_t i = 0; - for (const auto& it : m_ImageCache) { - pCACHEINFO[i].time = it.second->GetTimeCount(); - pCACHEINFO[i++].pStream = it.second->GetStream(); - } - FXSYS_qsort(pCACHEINFO, nCount, sizeof(CACHEINFO), compare); - uint32_t nTimeCount = m_nTimeCount; - - // Check if time value is about to roll over and reset all entries. - // The comparision is legal because uint32_t is an unsigned type. - if (nTimeCount + 1 < nTimeCount) { - for (i = 0; i < nCount; i++) - m_ImageCache[pCACHEINFO[i].pStream]->m_dwTimeCount = i; - m_nTimeCount = nCount; - } - - i = 0; - while (i + 15 < nCount) - ClearImageCacheEntry(pCACHEINFO[i++].pStream); - - while (i < nCount && m_nCacheSize > (uint32_t)dwLimitCacheSize) - ClearImageCacheEntry(pCACHEINFO[i++].pStream); - - FX_Free(pCACHEINFO); -} -void CPDF_PageRenderCache::ClearImageCacheEntry(CPDF_Stream* pStream) { - auto it = m_ImageCache.find(pStream); - if (it == m_ImageCache.end()) - return; - - m_nCacheSize -= it->second->EstimateSize(); - delete it->second; - m_ImageCache.erase(it); -} -uint32_t CPDF_PageRenderCache::EstimateSize() { - uint32_t dwSize = 0; - for (const auto& it : m_ImageCache) - dwSize += it.second->EstimateSize(); - - m_nCacheSize = dwSize; - return dwSize; -} -void CPDF_PageRenderCache::GetCachedBitmap(CPDF_Stream* pStream, - CFX_DIBSource*& pBitmap, - CFX_DIBSource*& pMask, - uint32_t& MatteColor, - bool bStdCS, - uint32_t GroupFamily, - bool bLoadMask, - CPDF_RenderStatus* pRenderStatus, - int32_t downsampleWidth, - int32_t downsampleHeight) { - CPDF_ImageCacheEntry* pEntry; - const auto it = m_ImageCache.find(pStream); - bool bFound = it != m_ImageCache.end(); - if (bFound) - pEntry = it->second; - else - pEntry = new CPDF_ImageCacheEntry(m_pPage->m_pDocument, pStream); - - m_nTimeCount++; - bool bAlreadyCached = pEntry->GetCachedBitmap( - pBitmap, pMask, MatteColor, m_pPage->m_pPageResources, bStdCS, - GroupFamily, bLoadMask, pRenderStatus, downsampleWidth, downsampleHeight); - - if (!bFound) - m_ImageCache[pStream] = pEntry; - - if (!bAlreadyCached) - m_nCacheSize += pEntry->EstimateSize(); -} -bool CPDF_PageRenderCache::StartGetCachedBitmap( - CPDF_Stream* pStream, - bool bStdCS, - uint32_t GroupFamily, - bool bLoadMask, - CPDF_RenderStatus* pRenderStatus, - int32_t downsampleWidth, - int32_t downsampleHeight) { - const auto it = m_ImageCache.find(pStream); - m_bCurFindCache = it != m_ImageCache.end(); - if (m_bCurFindCache) { - m_pCurImageCacheEntry = it->second; - } else { - m_pCurImageCacheEntry = - new CPDF_ImageCacheEntry(m_pPage->m_pDocument, pStream); - } - int ret = m_pCurImageCacheEntry->StartGetCachedBitmap( - pRenderStatus->m_pFormResource, m_pPage->m_pPageResources, bStdCS, - GroupFamily, bLoadMask, pRenderStatus, downsampleWidth, downsampleHeight); - if (ret == 2) - return true; - - m_nTimeCount++; - if (!m_bCurFindCache) - m_ImageCache[pStream] = m_pCurImageCacheEntry; - - if (!ret) - m_nCacheSize += m_pCurImageCacheEntry->EstimateSize(); - - return false; -} -bool CPDF_PageRenderCache::Continue(IFX_Pause* pPause) { - int ret = m_pCurImageCacheEntry->Continue(pPause); - if (ret == 2) - return true; - m_nTimeCount++; - if (!m_bCurFindCache) - m_ImageCache[m_pCurImageCacheEntry->GetStream()] = m_pCurImageCacheEntry; - if (!ret) - m_nCacheSize += m_pCurImageCacheEntry->EstimateSize(); - return false; -} -void CPDF_PageRenderCache::ResetBitmap(CPDF_Stream* pStream, - const CFX_DIBitmap* pBitmap) { - CPDF_ImageCacheEntry* pEntry; - const auto it = m_ImageCache.find(pStream); - if (it == m_ImageCache.end()) { - if (!pBitmap) - return; - pEntry = new CPDF_ImageCacheEntry(m_pPage->m_pDocument, pStream); - m_ImageCache[pStream] = pEntry; - } else { - pEntry = it->second; - } - m_nCacheSize -= pEntry->EstimateSize(); - pEntry->Reset(pBitmap); - m_nCacheSize += pEntry->EstimateSize(); -} CPDF_ImageCacheEntry::CPDF_ImageCacheEntry(CPDF_Document* pDoc, CPDF_Stream* pStream) : m_dwTimeCount(0), - m_pCurBitmap(nullptr), - m_pCurMask(nullptr), m_MatteColor(0), m_pRenderStatus(nullptr), m_pDocument(pDoc), m_pStream(pStream), + m_pCurBitmap(nullptr), + m_pCurMask(nullptr), m_dwCacheSize(0) {} CPDF_ImageCacheEntry::~CPDF_ImageCacheEntry() {} @@ -198,6 +44,7 @@ static uint32_t FPDF_ImageCache_EstimateImageSize(const CFX_DIBSource* pDIB) { (uint32_t)pDIB->GetPaletteSize() * 4 : 0; } + bool CPDF_ImageCacheEntry::GetCachedBitmap(CFX_DIBSource*& pBitmap, CFX_DIBSource*& pMask, uint32_t& MatteColor, @@ -214,9 +61,9 @@ bool CPDF_ImageCacheEntry::GetCachedBitmap(CFX_DIBSource*& pBitmap, MatteColor = m_MatteColor; return true; } - if (!pRenderStatus) { + if (!pRenderStatus) return false; - } + CPDF_RenderContext* pContext = pRenderStatus->GetContext(); CPDF_PageRenderCache* pPageRenderCache = pContext->GetPageCache(); m_dwTimeCount = pPageRenderCache->GetTimeCount(); @@ -244,11 +91,13 @@ CFX_DIBSource* CPDF_ImageCacheEntry::DetachBitmap() { m_pCurBitmap = nullptr; return pDIBSource; } + CFX_DIBSource* CPDF_ImageCacheEntry::DetachMask() { CFX_DIBSource* pDIBSource = m_pCurMask; m_pCurMask = nullptr; return pDIBSource; } + int CPDF_ImageCacheEntry::StartGetCachedBitmap(CPDF_Dictionary* pFormResources, CPDF_Dictionary* pPageResources, bool bStdCS, @@ -299,9 +148,9 @@ void CPDF_ImageCacheEntry::ContinueGetCachedBitmap() { int CPDF_ImageCacheEntry::Continue(IFX_Pause* pPause) { int ret = ((CPDF_DIBSource*)m_pCurBitmap)->ContinueLoadDIBSource(pPause); - if (ret == 2) { + if (ret == 2) return ret; - } + if (!ret) { delete m_pCurBitmap; m_pCurBitmap = nullptr; @@ -310,6 +159,7 @@ int CPDF_ImageCacheEntry::Continue(IFX_Pause* pPause) { ContinueGetCachedBitmap(); return 0; } + void CPDF_ImageCacheEntry::CalcSize() { m_dwCacheSize = FPDF_ImageCache_EstimateImageSize(m_pCachedBitmap.get()) + FPDF_ImageCache_EstimateImageSize(m_pCachedMask.get()); diff --git a/core/fpdfapi/render/cpdf_imagecacheentry.h b/core/fpdfapi/render/cpdf_imagecacheentry.h new file mode 100644 index 0000000000..e4481e0d73 --- /dev/null +++ b/core/fpdfapi/render/cpdf_imagecacheentry.h @@ -0,0 +1,71 @@ +// Copyright 2016 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#ifndef CORE_FPDFAPI_RENDER_CPDF_IMAGECACHEENTRY_H_ +#define CORE_FPDFAPI_RENDER_CPDF_IMAGECACHEENTRY_H_ + +#include <memory> + +#include "core/fxcrt/fx_system.h" + +class CFX_DIBitmap; +class CFX_DIBSource; +class CPDF_Dictionary; +class CPDF_Document; +class CPDF_RenderStatus; +class CPDF_Stream; +class IFX_Pause; + +class CPDF_ImageCacheEntry { + public: + CPDF_ImageCacheEntry(CPDF_Document* pDoc, CPDF_Stream* pStream); + ~CPDF_ImageCacheEntry(); + + void Reset(const CFX_DIBitmap* pBitmap); + bool GetCachedBitmap(CFX_DIBSource*& pBitmap, + CFX_DIBSource*& pMask, + uint32_t& MatteColor, + CPDF_Dictionary* pPageResources, + bool bStdCS, + uint32_t GroupFamily, + bool bLoadMask, + CPDF_RenderStatus* pRenderStatus, + int32_t downsampleWidth, + int32_t downsampleHeight); + uint32_t EstimateSize() const { return m_dwCacheSize; } + uint32_t GetTimeCount() const { return m_dwTimeCount; } + CPDF_Stream* GetStream() const { return m_pStream; } + + int StartGetCachedBitmap(CPDF_Dictionary* pFormResources, + CPDF_Dictionary* pPageResources, + bool bStdCS, + uint32_t GroupFamily, + bool bLoadMask, + CPDF_RenderStatus* pRenderStatus, + int32_t downsampleWidth, + int32_t downsampleHeight); + int Continue(IFX_Pause* pPause); + CFX_DIBSource* DetachBitmap(); + CFX_DIBSource* DetachMask(); + + int m_dwTimeCount; + uint32_t m_MatteColor; + + private: + void ContinueGetCachedBitmap(); + + CPDF_RenderStatus* m_pRenderStatus; + CPDF_Document* m_pDocument; + CPDF_Stream* m_pStream; + CFX_DIBSource* m_pCurBitmap; + CFX_DIBSource* m_pCurMask; + std::unique_ptr<CFX_DIBSource> m_pCachedBitmap; + std::unique_ptr<CFX_DIBSource> m_pCachedMask; + uint32_t m_dwCacheSize; + void CalcSize(); +}; + +#endif // CORE_FPDFAPI_RENDER_CPDF_IMAGECACHEENTRY_H_ diff --git a/core/fpdfapi/render/cpdf_imageloader.cpp b/core/fpdfapi/render/cpdf_imageloader.cpp index 3fb85dae40..77e21168f9 100644 --- a/core/fpdfapi/render/cpdf_imageloader.cpp +++ b/core/fpdfapi/render/cpdf_imageloader.cpp @@ -8,6 +8,7 @@ #include "core/fpdfapi/page/cpdf_image.h" #include "core/fpdfapi/page/cpdf_imageobject.h" +#include "core/fpdfapi/render/cpdf_imagecacheentry.h" #include "core/fpdfapi/render/cpdf_pagerendercache.h" #include "core/fpdfapi/render/cpdf_renderstatus.h" #include "core/fpdfapi/render/render_int.h" diff --git a/core/fpdfapi/render/cpdf_pagerendercache.cpp b/core/fpdfapi/render/cpdf_pagerendercache.cpp new file mode 100644 index 0000000000..faa9732f9b --- /dev/null +++ b/core/fpdfapi/render/cpdf_pagerendercache.cpp @@ -0,0 +1,143 @@ +// Copyright 2016 PDFium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com + +#include "core/fpdfapi/render/cpdf_pagerendercache.h" + +#include "core/fpdfapi/page/cpdf_page.h" +#include "core/fpdfapi/render/cpdf_imagecacheentry.h" +#include "core/fpdfapi/render/cpdf_renderstatus.h" + +namespace { + +struct CACHEINFO { + uint32_t time; + CPDF_Stream* pStream; +}; + +extern "C" { +static int compare(const void* data1, const void* data2) { + return ((CACHEINFO*)data1)->time - ((CACHEINFO*)data2)->time; +} +} // extern "C" + +} // namespace + +CPDF_PageRenderCache::CPDF_PageRenderCache(CPDF_Page* pPage) + : m_pPage(pPage), + m_pCurImageCacheEntry(nullptr), + m_nTimeCount(0), + m_nCacheSize(0), + m_bCurFindCache(false) {} + +CPDF_PageRenderCache::~CPDF_PageRenderCache() { + for (const auto& it : m_ImageCache) + delete it.second; +} + +void CPDF_PageRenderCache::CacheOptimization(int32_t dwLimitCacheSize) { + if (m_nCacheSize <= (uint32_t)dwLimitCacheSize) + return; + + size_t nCount = m_ImageCache.size(); + CACHEINFO* pCACHEINFO = FX_Alloc(CACHEINFO, nCount); + size_t i = 0; + for (const auto& it : m_ImageCache) { + pCACHEINFO[i].time = it.second->GetTimeCount(); + pCACHEINFO[i++].pStream = it.second->GetStream(); + } + FXSYS_qsort(pCACHEINFO, nCount, sizeof(CACHEINFO), compare); + uint32_t nTimeCount = m_nTimeCount; + + // Check if time value is about to roll over and reset all entries. + // The comparision is legal because uint32_t is an unsigned type. + if (nTimeCount + 1 < nTimeCount) { + for (i = 0; i < nCount; i++) + m_ImageCache[pCACHEINFO[i].pStream]->m_dwTimeCount = i; + m_nTimeCount = nCount; + } + + i = 0; + while (i + 15 < nCount) + ClearImageCacheEntry(pCACHEINFO[i++].pStream); + + while (i < nCount && m_nCacheSize > (uint32_t)dwLimitCacheSize) + ClearImageCacheEntry(pCACHEINFO[i++].pStream); + + FX_Free(pCACHEINFO); +} + +void CPDF_PageRenderCache::ClearImageCacheEntry(CPDF_Stream* pStream) { + auto it = m_ImageCache.find(pStream); + if (it == m_ImageCache.end()) + return; + + m_nCacheSize -= it->second->EstimateSize(); + delete it->second; + m_ImageCache.erase(it); +} + +bool CPDF_PageRenderCache::StartGetCachedBitmap( + CPDF_Stream* pStream, + bool bStdCS, + uint32_t GroupFamily, + bool bLoadMask, + CPDF_RenderStatus* pRenderStatus, + int32_t downsampleWidth, + int32_t downsampleHeight) { + const auto it = m_ImageCache.find(pStream); + m_bCurFindCache = it != m_ImageCache.end(); + if (m_bCurFindCache) { + m_pCurImageCacheEntry = it->second; + } else { + m_pCurImageCacheEntry = + new CPDF_ImageCacheEntry(m_pPage->m_pDocument, pStream); + } + int ret = m_pCurImageCacheEntry->StartGetCachedBitmap( + pRenderStatus->m_pFormResource, m_pPage->m_pPageResources, bStdCS, + GroupFamily, bLoadMask, pRenderStatus, downsampleWidth, downsampleHeight); + if (ret == 2) + return true; + + m_nTimeCount++; + if (!m_bCurFindCache) + m_ImageCache[pStream] = m_pCurImageCacheEntry; + + if (!ret) + m_nCacheSize += m_pCurImageCacheEntry->EstimateSize(); + + return false; +} + +bool CPDF_PageRenderCache::Continue(IFX_Pause* pPause) { + int ret = m_pCurImageCacheEntry->Continue(pPause); + if (ret == 2) + return true; + + m_nTimeCount++; + if (!m_bCurFindCache) + m_ImageCache[m_pCurImageCacheEntry->GetStream()] = m_pCurImageCacheEntry; + if (!ret) + m_nCacheSize += m_pCurImageCacheEntry->EstimateSize(); + return false; +} + +void CPDF_PageRenderCache::ResetBitmap(CPDF_Stream* pStream, + const CFX_DIBitmap* pBitmap) { + CPDF_ImageCacheEntry* pEntry; + const auto it = m_ImageCache.find(pStream); + if (it == m_ImageCache.end()) { + if (!pBitmap) + return; + + pEntry = new CPDF_ImageCacheEntry(m_pPage->m_pDocument, pStream); + m_ImageCache[pStream] = pEntry; + } else { + pEntry = it->second; + } + m_nCacheSize -= pEntry->EstimateSize(); + pEntry->Reset(pBitmap); + m_nCacheSize += pEntry->EstimateSize(); +} diff --git a/core/fpdfapi/render/cpdf_pagerendercache.h b/core/fpdfapi/render/cpdf_pagerendercache.h index 0877e6cb58..6c9ed76911 100644 --- a/core/fpdfapi/render/cpdf_pagerendercache.h +++ b/core/fpdfapi/render/cpdf_pagerendercache.h @@ -24,40 +24,28 @@ class CPDF_PageRenderCache { explicit CPDF_PageRenderCache(CPDF_Page* pPage); ~CPDF_PageRenderCache(); - uint32_t EstimateSize(); void CacheOptimization(int32_t dwLimitCacheSize); uint32_t GetTimeCount() const { return m_nTimeCount; } - void SetTimeCount(uint32_t dwTimeCount) { m_nTimeCount = dwTimeCount; } - - void GetCachedBitmap(CPDF_Stream* pStream, - CFX_DIBSource*& pBitmap, - CFX_DIBSource*& pMask, - uint32_t& MatteColor, - bool bStdCS = false, - uint32_t GroupFamily = 0, - bool bLoadMask = false, - CPDF_RenderStatus* pRenderStatus = nullptr, - int32_t downsampleWidth = 0, - int32_t downsampleHeight = 0); void ResetBitmap(CPDF_Stream* pStream, const CFX_DIBitmap* pBitmap); - void ClearImageCacheEntry(CPDF_Stream* pStream); CPDF_Page* GetPage() const { return m_pPage; } CPDF_ImageCacheEntry* GetCurImageCacheEntry() const { return m_pCurImageCacheEntry; } bool StartGetCachedBitmap(CPDF_Stream* pStream, - bool bStdCS = false, - uint32_t GroupFamily = 0, - bool bLoadMask = false, - CPDF_RenderStatus* pRenderStatus = nullptr, - int32_t downsampleWidth = 0, - int32_t downsampleHeight = 0); + bool bStdCS, + uint32_t GroupFamily, + bool bLoadMask, + CPDF_RenderStatus* pRenderStatus, + int32_t downsampleWidth, + int32_t downsampleHeight); bool Continue(IFX_Pause* pPause); - protected: + private: + void ClearImageCacheEntry(CPDF_Stream* pStream); + CPDF_Page* const m_pPage; CPDF_ImageCacheEntry* m_pCurImageCacheEntry; std::map<CPDF_Stream*, CPDF_ImageCacheEntry*> m_ImageCache; diff --git a/core/fpdfapi/render/render_int.h b/core/fpdfapi/render/render_int.h index dfad6b14c6..ca827368bc 100644 --- a/core/fpdfapi/render/render_int.h +++ b/core/fpdfapi/render/render_int.h @@ -49,56 +49,6 @@ class CPDF_Type3Glyphs; class CPDF_Type3Char; class CPDF_Type3Font; -class CPDF_ImageCacheEntry { - public: - CPDF_ImageCacheEntry(CPDF_Document* pDoc, CPDF_Stream* pStream); - ~CPDF_ImageCacheEntry(); - - void Reset(const CFX_DIBitmap* pBitmap); - bool GetCachedBitmap(CFX_DIBSource*& pBitmap, - CFX_DIBSource*& pMask, - uint32_t& MatteColor, - CPDF_Dictionary* pPageResources, - bool bStdCS = false, - uint32_t GroupFamily = 0, - bool bLoadMask = false, - CPDF_RenderStatus* pRenderStatus = nullptr, - int32_t downsampleWidth = 0, - int32_t downsampleHeight = 0); - uint32_t EstimateSize() const { return m_dwCacheSize; } - uint32_t GetTimeCount() const { return m_dwTimeCount; } - CPDF_Stream* GetStream() const { return m_pStream; } - void SetTimeCount(uint32_t dwTimeCount) { m_dwTimeCount = dwTimeCount; } - int m_dwTimeCount; - - public: - int StartGetCachedBitmap(CPDF_Dictionary* pFormResources, - CPDF_Dictionary* pPageResources, - bool bStdCS = false, - uint32_t GroupFamily = 0, - bool bLoadMask = false, - CPDF_RenderStatus* pRenderStatus = nullptr, - int32_t downsampleWidth = 0, - int32_t downsampleHeight = 0); - int Continue(IFX_Pause* pPause); - CFX_DIBSource* DetachBitmap(); - CFX_DIBSource* DetachMask(); - CFX_DIBSource* m_pCurBitmap; - CFX_DIBSource* m_pCurMask; - uint32_t m_MatteColor; - CPDF_RenderStatus* m_pRenderStatus; - - protected: - void ContinueGetCachedBitmap(); - - CPDF_Document* m_pDocument; - CPDF_Stream* m_pStream; - std::unique_ptr<CFX_DIBSource> m_pCachedBitmap; - std::unique_ptr<CFX_DIBSource> m_pCachedMask; - uint32_t m_dwCacheSize; - void CalcSize(); -}; - typedef struct { FX_FLOAT m_DecodeMin; FX_FLOAT m_DecodeStep; |