From 267c6f2ac71f92999e969232431ba04678e7437e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 07:54:39 +0200 Subject: Adding upstream version 4:24.2.0. Signed-off-by: Daniel Baumann --- svx/source/svdraw/svdetc.cxx | 704 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 704 insertions(+) create mode 100644 svx/source/svdraw/svdetc.cxx (limited to 'svx/source/svdraw/svdetc.cxx') diff --git a/svx/source/svdraw/svdetc.cxx b/svx/source/svdraw/svdetc.cxx new file mode 100644 index 0000000000..e5f99a8f8f --- /dev/null +++ b/svx/source/svdraw/svdetc.cxx @@ -0,0 +1,704 @@ +/* -*- 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 . + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +using namespace ::com::sun::star; + +// Global data of the DrawingEngine +SdrGlobalData::SdrGlobalData() +{ + if (!utl::ConfigManager::IsFuzzing()) + { + svx::ExtrusionBar::RegisterInterface(); + svx::FontworkBar::RegisterInterface(); + } +} + +const LocaleDataWrapper& SdrGlobalData::GetLocaleData() +{ + return GetSysLocale().GetLocaleData(); +} + +namespace { + +struct TheSdrGlobalData: public rtl::Static {}; + +} + +SdrGlobalData & GetSdrGlobalData() { + return TheSdrGlobalData::get(); +} + +OLEObjCache::OLEObjCache() +{ + if (!utl::ConfigManager::IsFuzzing()) + { +// This limit is only useful on 32-bit windows, where we can run out of virtual memory (see tdf#95579) +// For everything else, we are better off keeping it in main memory rather than using our hacky page-out thing +#if defined _WIN32 && !defined _WIN64 + nSize = officecfg::Office::Common::Cache::DrawingEngine::OLE_Objects::get(); +#else + nSize = SAL_MAX_INT32; // effectively disable the page-out mechanism +#endif + } + else + nSize = 100; + pTimer.reset( new AutoTimer( "svx OLEObjCache pTimer UnloadCheck" ) ); + pTimer->SetInvokeHandler( LINK(this, OLEObjCache, UnloadCheckHdl) ); + pTimer->SetTimeout(20000); + pTimer->SetStatic(); +} + +OLEObjCache::~OLEObjCache() +{ + pTimer->Stop(); +} + +IMPL_LINK_NOARG(OLEObjCache, UnloadCheckHdl, Timer*, void) +{ + if (nSize >= maObjs.size()) + return; + + // more objects than configured cache size try to remove objects + // of course not the freshly inserted one at nIndex=0 + size_t nCount2 = maObjs.size(); + size_t nIndex = nCount2-1; + while( nIndex && nCount2 > nSize ) + { + SdrOle2Obj* pUnloadObj = maObjs[nIndex--]; + if (!pUnloadObj) + continue; + + try + { + // it is important to get object without reinitialization to avoid reentrance + const uno::Reference< embed::XEmbeddedObject > & xUnloadObj = pUnloadObj->GetObjRef_NoInit(); + + bool bUnload = !xUnloadObj || SdrOle2Obj::CanUnloadRunningObj( xUnloadObj, pUnloadObj->GetAspect() ); + + // check whether the object can be unloaded before looking for the parent objects + if ( xUnloadObj.is() && bUnload ) + { + uno::Reference< frame::XModel > xUnloadModel( xUnloadObj->getComponent(), uno::UNO_QUERY ); + if ( xUnloadModel.is() ) + { + for (SdrOle2Obj* pCacheObj : maObjs) + { + if ( pCacheObj && pCacheObj != pUnloadObj ) + { + uno::Reference< frame::XModel > xParentModel = pCacheObj->GetParentXModel(); + if ( xUnloadModel == xParentModel ) + { + bUnload = false; // the object has running embedded objects + break; + } + } + } + } + } + + if (bUnload && UnloadObj(*pUnloadObj)) + { + // object was successfully unloaded + RemoveObj(pUnloadObj); + nCount2 = std::min(nCount2 - 1, maObjs.size()); + if (nIndex >= nCount2) + nIndex = nCount2 - 1; + } + } + catch( uno::Exception& ) + {} + } +} + +void OLEObjCache::InsertObj(SdrOle2Obj* pObj) +{ + if (!maObjs.empty()) + { + SdrOle2Obj* pExistingObj = maObjs.front(); + if ( pObj == pExistingObj ) + // the object is already on the top, nothing has to be changed + return; + } + + // get the old position of the object to know whether it is already in container + std::vector::iterator it = std::find(maObjs.begin(), maObjs.end(), pObj); + bool bFound = it != maObjs.end(); + + if (bFound) + maObjs.erase(it); + // insert object into first position + maObjs.insert(maObjs.begin(), pObj); + + // if a new object was inserted, recalculate the cache + if (!bFound) + pTimer->Invoke(); + + if (!bFound || !pTimer->IsActive()) + pTimer->Start(); +} + +void OLEObjCache::RemoveObj(SdrOle2Obj* pObj) +{ + std::vector::iterator it = std::find(maObjs.begin(), maObjs.end(), pObj); + if (it != maObjs.end()) + maObjs.erase(it); + if (maObjs.empty()) + pTimer->Stop(); +} + +size_t OLEObjCache::size() const +{ + return maObjs.size(); +} + +SdrOle2Obj* OLEObjCache::operator[](size_t nPos) +{ + return maObjs[nPos]; +} + +const SdrOle2Obj* OLEObjCache::operator[](size_t nPos) const +{ + return maObjs[nPos]; +} + +bool OLEObjCache::UnloadObj(SdrOle2Obj& rObj) +{ + bool bUnloaded = false; + + //#i80528# The old mechanism is completely useless, only taking into account if + // in all views the GrafDraft feature is used. This will nearly never have been the + // case since no one ever used this option. + + // A much better (and working) criteria would be the VOC contact count. + // The question is what will happen when i make it work now suddenly? I + // will try it for 2.4. + const sdr::contact::ViewContact& rViewContact = rObj.GetViewContact(); + const bool bVisible(rViewContact.HasViewObjectContacts()); + + if(!bVisible) + { + bUnloaded = rObj.Unload(); + } + + return bUnloaded; +} + +std::optional GetDraftFillColor(const SfxItemSet& rSet) +{ + drawing::FillStyle eFill=rSet.Get(XATTR_FILLSTYLE).GetValue(); + + switch(eFill) + { + case drawing::FillStyle_SOLID: + { + return rSet.Get(XATTR_FILLCOLOR).GetColorValue(); + } + case drawing::FillStyle_HATCH: + { + Color aCol1(rSet.Get(XATTR_FILLHATCH).GetHatchValue().GetColor()); + Color aCol2(COL_WHITE); + + // when hatched background is activated, use object fill color as hatch color + bool bFillHatchBackground = rSet.Get(XATTR_FILLBACKGROUND).GetValue(); + if(bFillHatchBackground) + { + aCol2 = rSet.Get(XATTR_FILLCOLOR).GetColorValue(); + } + + const basegfx::BColor aAverageColor(basegfx::average(aCol1.getBColor(), aCol2.getBColor())); + return Color(aAverageColor); + } + case drawing::FillStyle_GRADIENT: { + const basegfx::BGradient& rGrad=rSet.Get(XATTR_FILLGRADIENT).GetGradientValue(); + Color aCol1(Color(rGrad.GetColorStops().front().getStopColor())); + Color aCol2(Color(rGrad.GetColorStops().back().getStopColor())); + const basegfx::BColor aAverageColor(basegfx::average(aCol1.getBColor(), aCol2.getBColor())); + return Color(aAverageColor); + } + case drawing::FillStyle_BITMAP: + { + Bitmap aBitmap(rSet.Get(XATTR_FILLBITMAP).GetGraphicObject().GetGraphic().GetBitmapEx().GetBitmap()); + const Size aSize(aBitmap.GetSizePixel()); + const sal_uInt32 nWidth = aSize.Width(); + const sal_uInt32 nHeight = aSize.Height(); + if (nWidth <= 0 || nHeight <= 0) + return {}; + + BitmapScopedReadAccess pAccess(aBitmap); + + if (pAccess) + { + sal_uInt32 nRt(0); + sal_uInt32 nGn(0); + sal_uInt32 nBl(0); + const sal_uInt32 nMaxSteps(8); + const sal_uInt32 nXStep((nWidth > nMaxSteps) ? nWidth / nMaxSteps : 1); + const sal_uInt32 nYStep((nHeight > nMaxSteps) ? nHeight / nMaxSteps : 1); + sal_uInt32 nCount(0); + + for(sal_uInt32 nY(0); nY < nHeight; nY += nYStep) + { + for(sal_uInt32 nX(0); nX < nWidth; nX += nXStep) + { + const BitmapColor& rCol2 = pAccess->GetColor(nY, nX); + + nRt += rCol2.GetRed(); + nGn += rCol2.GetGreen(); + nBl += rCol2.GetBlue(); + nCount++; + } + } + + nRt /= nCount; + nGn /= nCount; + nBl /= nCount; + + return Color(sal_uInt8(nRt), sal_uInt8(nGn), sal_uInt8(nBl)); + } + break; + } + default: break; + } + + return {}; +} + +std::unique_ptr SdrMakeOutliner(OutlinerMode nOutlinerMode, SdrModel& rModel) +{ + SfxItemPool* pPool = &rModel.GetItemPool(); + std::unique_ptr pOutl(new SdrOutliner( pPool, nOutlinerMode )); + pOutl->SetEditTextObjectPool( pPool ); + pOutl->SetStyleSheetPool( static_cast(rModel.GetStyleSheetPool())); + pOutl->SetDefTab(rModel.GetDefaultTabulator()); + Outliner::SetForbiddenCharsTable(rModel.GetForbiddenCharsTable()); + pOutl->SetAsianCompressionMode(rModel.GetCharCompressType()); + pOutl->SetKernAsianPunctuation(rModel.IsKernAsianPunctuation()); + pOutl->SetAddExtLeading(rModel.IsAddExtLeading()); + return pOutl; +} + +std::vector>>& ImpGetUserMakeObjHdl() +{ + SdrGlobalData& rGlobalData=GetSdrGlobalData(); + return rGlobalData.aUserMakeObjHdl; +} + +bool SearchOutlinerItems(const SfxItemSet& rSet, bool bInklDefaults, bool* pbOnlyEE) +{ + bool bHas=false; + bool bOnly=true; + bool bLookOnly=pbOnlyEE!=nullptr; + SfxWhichIter aIter(rSet); + sal_uInt16 nWhich=aIter.FirstWhich(); + while (((bLookOnly && bOnly) || !bHas) && nWhich!=0) { + // For bInklDefaults, the entire Which range is decisive, + // in other cases only the set items are. + // Disabled and DontCare are regarded as holes in the Which range. + SfxItemState eState=aIter.GetItemState(); + if ((eState==SfxItemState::DEFAULT && bInklDefaults) || eState==SfxItemState::SET) { + if (nWhichEE_ITEMS_END) bOnly=false; + else bHas=true; + } + nWhich=aIter.NextWhich(); + } + if (!bHas) bOnly=false; + if (pbOnlyEE!=nullptr) *pbOnlyEE=bOnly; + return bHas; +} + +WhichRangesContainer RemoveWhichRange(const WhichRangesContainer& pOldWhichTable, sal_uInt16 nRangeBeg, sal_uInt16 nRangeEnd) +{ + // Six possible cases (per range): + // [Beg..End] [nRangeBeg, nRangeEnd], to delete + // [b..e] [b..e] [b..e] Cases 1,3,2: doesn't matter, delete, doesn't matter + Ranges + // [b........e] [b........e] Cases 4,5 : shrink range | in + // [b......................e] Case 6 : splitting + pOldWhichTable + std::vector buf; + for (const auto & rPair : pOldWhichTable) { + auto const begin = rPair.first; + auto const end = rPair.second; + if (end < nRangeBeg || begin > nRangeEnd) { // cases 1, 2 + buf.push_back({begin, end}); + } else if (begin >= nRangeBeg && end <= nRangeEnd) { // case 3 + // drop + } else if (end <= nRangeEnd) { // case 4 + buf.push_back({begin, nRangeBeg - 1}); + } else if (begin >= nRangeBeg) { // case 5 + buf.push_back({nRangeEnd + 1, end}); + } else { // case 6 + buf.push_back({begin, nRangeBeg - 1}); + buf.push_back({nRangeEnd + 1, end}); + } + } + std::unique_ptr pNewWhichTable(new WhichPair[buf.size()]); + std::copy(buf.begin(), buf.end(), pNewWhichTable.get()); + return WhichRangesContainer(std::move(pNewWhichTable), buf.size()); +} + + +SvdProgressInfo::SvdProgressInfo( const Link&_rLink ) +{ + maLink = _rLink; + m_nSumCurAction = 0; + + m_nObjCount = 0; + m_nCurObj = 0; + + m_nActionCount = 0; + m_nCurAction = 0; + + m_nInsertCount = 0; + m_nCurInsert = 0; +} + +void SvdProgressInfo::Init( size_t nObjCount ) +{ + m_nObjCount = nObjCount; +} + +bool SvdProgressInfo::ReportActions( size_t nActionCount ) +{ + m_nSumCurAction += nActionCount; + m_nCurAction += nActionCount; + if(m_nCurAction > m_nActionCount) + m_nCurAction = m_nActionCount; + + return maLink.Call(nullptr); +} + +void SvdProgressInfo::ReportInserts( size_t nInsertCount ) +{ + m_nSumCurAction += nInsertCount; + m_nCurInsert += nInsertCount; + + maLink.Call(nullptr); +} + +void SvdProgressInfo::ReportRescales( size_t nRescaleCount ) +{ + m_nSumCurAction += nRescaleCount; + maLink.Call(nullptr); +} + +void SvdProgressInfo::SetActionCount( size_t nActionCount ) +{ + m_nActionCount = nActionCount; +} + +void SvdProgressInfo::SetInsertCount( size_t nInsertCount ) +{ + m_nInsertCount = nInsertCount; +} + +void SvdProgressInfo::SetNextObject() +{ + m_nActionCount = 0; + m_nCurAction = 0; + + m_nInsertCount = 0; + m_nCurInsert = 0; + + m_nCurObj++; + ReportActions(0); +} + +// #i101872# isolate GetTextEditBackgroundColor to tooling; it will anyways only be used as long +// as text edit is not running on overlay + +namespace +{ + std::optional impGetSdrObjListFillColor( + const SdrObjList& rList, + const Point& rPnt, + const SdrPageView& rTextEditPV, + const SdrLayerIDSet& rVisLayers) + { + bool bMaster(rList.getSdrPageFromSdrObjList() && rList.getSdrPageFromSdrObjList()->IsMasterPage()); + + for(size_t no(rList.GetObjCount()); no > 0; ) + { + no--; + SdrObject* pObj = rList.GetObj(no); + SdrObjList* pOL = pObj->GetSubList(); + + if(pOL) + { + // group object + if (auto oColor = impGetSdrObjListFillColor(*pOL, rPnt, rTextEditPV, rVisLayers)) + return oColor; + } + else + { + SdrTextObj* pText = DynCastSdrTextObj(pObj); + + // Exclude zero master page object (i.e. background shape) from color query + if(pText + && pObj->IsClosedObj() + && (!bMaster || (!pObj->IsNotVisibleAsMaster() && 0 != no)) + && pObj->GetCurrentBoundRect().Contains(rPnt) + && !pText->IsHideContour() + && SdrObjectPrimitiveHit(*pObj, rPnt, {0, 0}, rTextEditPV, &rVisLayers, false)) + { + if (auto oColor = GetDraftFillColor(pObj->GetMergedItemSet())) + return oColor; + } + } + } + + return {}; + } + + std::optional impGetSdrPageFillColor( + const SdrPage& rPage, + const Point& rPnt, + const SdrPageView& rTextEditPV, + const SdrLayerIDSet& rVisLayers, + bool bSkipBackgroundShape) + { + if (auto oColor = impGetSdrObjListFillColor(rPage, rPnt, rTextEditPV, rVisLayers)) + return oColor; + + if(!rPage.IsMasterPage()) + { + if(rPage.TRG_HasMasterPage()) + { + SdrLayerIDSet aSet(rVisLayers); + aSet &= rPage.TRG_GetMasterPageVisibleLayers(); + SdrPage& rMasterPage = rPage.TRG_GetMasterPage(); + + // Don't fall back to background shape on + // master pages. This is later handled by + // GetBackgroundColor, and is necessary to cater for + // the silly ordering: 1. shapes, 2. master page + // shapes, 3. page background, 4. master page + // background. + if (auto oColor = impGetSdrPageFillColor(rMasterPage, rPnt, rTextEditPV, aSet, true)) + return oColor; + } + } + + // Only now determine background color from background shapes + if(!bSkipBackgroundShape) + { + return rPage.GetPageBackgroundColor(); + } + + return {}; + } + + Color impCalcBackgroundColor( + const tools::Rectangle& rArea, + const SdrPageView& rTextEditPV, + const SdrPage& rPage) + { + svtools::ColorConfig aColorConfig; + Color aBackground(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor); + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + + if(!rStyleSettings.GetHighContrastMode()) + { + // search in page + const sal_uInt16 SPOTCOUNT(5); + Point aSpotPos[SPOTCOUNT]; + Color aSpotColor[SPOTCOUNT]; + sal_uInt32 nHeight( rArea.GetSize().Height() ); + sal_uInt32 nWidth( rArea.GetSize().Width() ); + sal_uInt32 nWidth14 = nWidth / 4; + sal_uInt32 nHeight14 = nHeight / 4; + sal_uInt32 nWidth34 = ( 3 * nWidth ) / 4; + sal_uInt32 nHeight34 = ( 3 * nHeight ) / 4; + + sal_uInt16 i; + for ( i = 0; i < SPOTCOUNT; i++ ) + { + // five spots are used + switch ( i ) + { + case 0 : + { + // Center-Spot + aSpotPos[i] = rArea.Center(); + } + break; + + case 1 : + { + // TopLeft-Spot + aSpotPos[i] = rArea.TopLeft(); + aSpotPos[i].AdjustX(nWidth14 ); + aSpotPos[i].AdjustY(nHeight14 ); + } + break; + + case 2 : + { + // TopRight-Spot + aSpotPos[i] = rArea.TopLeft(); + aSpotPos[i].AdjustX(nWidth34 ); + aSpotPos[i].AdjustY(nHeight14 ); + } + break; + + case 3 : + { + // BottomLeft-Spot + aSpotPos[i] = rArea.TopLeft(); + aSpotPos[i].AdjustX(nWidth14 ); + aSpotPos[i].AdjustY(nHeight34 ); + } + break; + + case 4 : + { + // BottomRight-Spot + aSpotPos[i] = rArea.TopLeft(); + aSpotPos[i].AdjustX(nWidth34 ); + aSpotPos[i].AdjustY(nHeight34 ); + } + break; + + } + + aSpotColor[i] = + impGetSdrPageFillColor(rPage, aSpotPos[i], rTextEditPV, rTextEditPV.GetVisibleLayers(), false).value_or(COL_WHITE); + } + + sal_uInt16 aMatch[SPOTCOUNT]; + + for ( i = 0; i < SPOTCOUNT; i++ ) + { + // were same spot colors found? + aMatch[i] = 0; + + for ( sal_uInt16 j = 0; j < SPOTCOUNT; j++ ) + { + if( j != i ) + { + if( aSpotColor[i] == aSpotColor[j] ) + { + aMatch[i]++; + } + } + } + } + + // highest weight to center spot + aBackground = aSpotColor[0]; + + for ( sal_uInt16 nMatchCount = SPOTCOUNT - 1; nMatchCount > 1; nMatchCount-- ) + { + // which spot color was found most? + for ( i = 0; i < SPOTCOUNT; i++ ) + { + if( aMatch[i] == nMatchCount ) + { + aBackground = aSpotColor[i]; + nMatchCount = 1; // break outer for-loop + break; + } + } + } + } + + return aBackground; + } +} // end of anonymous namespace + +Color GetTextEditBackgroundColor(const SdrObjEditView& rView) +{ + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + + if(!rStyleSettings.GetHighContrastMode()) + { + SdrTextObj* pText = rView.GetTextEditObject(); + + if(pText && pText->IsClosedObj()) + { + sdr::table::SdrTableObj* pTable = dynamic_cast< sdr::table::SdrTableObj * >( pText ); + + if( pTable ) + if (auto oColor = GetDraftFillColor(pTable->GetActiveCellItemSet())) + return *oColor; + + if (auto oColor = GetDraftFillColor(pText->GetMergedItemSet())) + return *oColor; + } + + if (pText) + { + SdrPageView* pTextEditPV = rView.GetTextEditPageView(); + + if(pTextEditPV) + { + Point aPvOfs(pText->GetTextEditOffset()); + const SdrPage* pPg = pTextEditPV->GetPage(); + + if(pPg) + { + tools::Rectangle aSnapRect( pText->GetSnapRect() ); + aSnapRect.Move(aPvOfs.X(), aPvOfs.Y()); + + return impCalcBackgroundColor(aSnapRect, *pTextEditPV, *pPg); + } + } + } + } + + return svtools::ColorConfig().GetColorValue(svtools::DOCCOLOR).nColor; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3