/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
namespace
{ struct private_aImplSVData : public rtl::Static<ImplSVData, private_aImplSVData> {}; /// Default instance ensures that ImplSVData::mpHelpData is never null. struct private_aImplSVHelpData : public rtl::Static<ImplSVHelpData, private_aImplSVHelpData> {};
/// Default instance ensures that ImplSVData::mpWinData is never null. struct private_aImplSVWinData : public rtl::Static<ImplSVWinData, private_aImplSVWinData> {};
class SystemDependentDataBuffer final : public basegfx::SystemDependentDataManager
{ private:
std::mutex m_aMutex;
std::unique_ptr<AutoTimer> maTimer;
EntryMap maEntries;
void endUsage(basegfx::SystemDependentData_SharedPtr& rData) override
{ // tdf#163428 prepare space for entry to hold to avoid early deletion
basegfx::SystemDependentData_SharedPtr aToBeDeletedEntry;
{ // lock m_aMutex in own scope
std::unique_lock aGuard(m_aMutex);
EntryMap::iterator aFound(maEntries.find(rData));
if(aFound != maEntries.end())
{ // tdf#163428 ensure to hold/not delete entry while m_aMutex is locked
aToBeDeletedEntry = aFound->first;
// remove from list
maEntries.erase(aFound);
}
}
// tdf#163428 aToBeDeletedEntry will be destructed, thus the // entry referenced by SharedPtr may be deleted now
}
aTmpEntries = std::move(maEntries);
} // we need to destruct the entries outside the lock, because // we might call back into endUsage() and that will take the lock again and deadlock.
aTmpEntries.clear();
}
};
IMPL_LINK_NOARG(SystemDependentDataBuffer, implTimeoutHdl, Timer *, void)
{ // tdf#163428 prepare a temporary list for SystemDependentData_SharedPtr // entries that need to be removed from the unordered_map, but do not need // locking m_aMutex
::std::vector<basegfx::SystemDependentData_SharedPtr> aToBeDeletedEntries;
{ // lock m_aMutex in own scope
std::unique_lock aGuard(m_aMutex);
EntryMap::iterator aIter(maEntries.begin());
while(aIter != maEntries.end())
{ if(aIter->second)
{
aIter->second--;
++aIter;
} else
{ // tdf#163428 Do not potentially directly delete SystemDependentData_SharedPtr // entries in the unordered_map (maEntries). That can/would happen when the shared_ptr // has only one reference left. This can cause problems, e.g. we have // BufferedData_ModifiedBitmapEx which can contain a Bitmap with added // DataBuffers itself, thus deleting this here *directly* would trigger e.g. // endUsage above. That would then block when we would still hold m_aMutex. // This can potentially be the case with other derivations of // basegfx::SystemDependentData, too. // To avoid this, protect the part that needs protection by the m_aMutex, that // is the modification of the unordered_map itself. Cleaning up the list entries can be // done after this, without holding the lock. // Thus, remember the SystemDependentData_SharedPtr in a temporary list by adding // a reference/shared_ptr to it to guarantee it gets not deleted when it gets removed // from the unordered_map. // Anyways, only locking while manipulating the list is better, destruction of // objects may be expensive and hold m_aMutex longer than necessary.
aToBeDeletedEntries.push_back(aIter->first);
// remove from list. This decrements the shared_ptr, but delete is avoided
aIter = maEntries.erase(aIter);
}
}
if (maEntries.empty())
maTimer->Stop();
}
// tdf#163428 here aToBeDeletedEntries will be destroyed, the entries will be // decremented and potentially deleted. These are of type SystemDependentData_SharedPtr, // so we do not need to do anything explicitly here
}
}
/// Returns either the application window, or the default GL context window
vcl::Window* ImplGetDefaultWindow()
{
ImplSVData* pSVData = ImplGetSVData(); if (pSVData->maFrameData.mpAppWin) return pSVData->maFrameData.mpAppWin; else return ImplGetDefaultContextWindow();
}
/// returns the default window created to hold the persistent VCL GL context.
vcl::Window *ImplGetDefaultContextWindow()
{
ImplSVData* pSVData = ImplGetSVData();
// Double check locking on mpDefaultWin. if ( !pSVData->mpDefaultWin )
{
SolarMutexGuard aGuard;
if (!pSVData->mpDefaultWin && !pSVData->mbDeInit)
{ try
{
SAL_INFO( "vcl", "ImplGetDefaultWindow(): No AppWindow" );
// If current one is the static, clean it up to avoid having lingering references. if (pSVData->mpWinData == &private_aImplSVWinData::get())
{
pSVData->mpWinData->mpFocusWin.reset();
}
pSVData->mpWinData = pSVWinData; if (pSVData->mpWinData == nullptr)
{
pSVData->mpWinData = &private_aImplSVWinData::get(); // Never leave it null.
}
}
void ImplSVData::dropCaches()
{ // we are iterating over a map and doing erase while inside a loop which is doing erase // hence we can't use clear() here
maGDIData.maScaleCache.remove_if([](const lru_scale_cache::key_value_pair_t&)
{ returntrue; });
// copy, some caches self-delete on emptying, e.g. SwOLELRUCache auto aCacheOwners = maCacheOwners; for (CacheOwner* pCacheOwner : aCacheOwners)
pCacheOwner->dropCaches();
}
CacheOwner::CacheOwner()
{ if (ImplSVData* pSVData = ImplGetSVData())
{
pSVData->registerCacheOwner(*this); return;
}
SAL_WARN("vcl.app", "Cache owner ctor before ImplSVData created. This is useless.");
}
CacheOwner::~CacheOwner()
{ if (ImplSVData* pSVData = ImplGetSVData())
pSVData->deregisterCacheOwner(*this);
}
for (auto it = maGDIData.maScaleCache.begin();
it != maGDIData.maScaleCache.end(); ++it)
{
rState.append("\n\t");
rState.append(static_cast<sal_Int32>(it->first.maDestSize.Width()));
rState.append("x");
rState.append(static_cast<sal_Int32>(it->first.maDestSize.Height()));
}
if (mpBlendFrameCache)
{
rState.append("\nBlendFrameCache:");
rState.append("\n\t");
rState.append(static_cast<sal_Int32>(mpBlendFrameCache->m_aLastSize.Width()));
rState.append("x");
rState.append(static_cast<sal_Int32>(mpBlendFrameCache->m_aLastSize.Height()));
}
for (CacheOwner* pCacheOwner : maCacheOwners)
pCacheOwner->dumpState(rState);
}
ImplSVHelpData* CreateSVHelpData()
{ if (!comphelper::LibreOfficeKit::isActive()) return nullptr;
void DestroySVHelpData(ImplSVHelpData* pSVHelpData)
{ if (!comphelper::LibreOfficeKit::isActive()) return;
// Change the SVData's help date if necessary if(ImplGetSVData()->mpHelpData == pSVHelpData)
{
ImplGetSVData()->mpHelpData = &private_aImplSVHelpData::get();
}
void SetSVHelpData(ImplSVHelpData* pSVHelpData)
{ if (!comphelper::LibreOfficeKit::isActive()) return;
ImplSVData* pSVData = ImplGetSVData(); if (pSVData->mpHelpData == pSVHelpData) return;
// If current one is the static, clean it up to avoid having lingering references. if (pSVData->mpHelpData == &private_aImplSVHelpData::get())
{
pSVData->mpHelpData->mpHelpWin.reset();
}
pSVData->mpHelpData = pSVHelpData; if (pSVData->mpHelpData == nullptr)
{
pSVData->mpHelpData = &private_aImplSVHelpData::get(); // Never leave it null.
}
}
ImplSVAppData::ImplSVAppData()
{
m_bUseSystemLoop = getenv("SAL_USE_SYSTEM_LOOP") != nullptr;
SAL_WARN_IF(m_bUseSystemLoop, "vcl.schedule", "Overriding to run LO on system event loop!");
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.