office-gobmx/sc/inc/attrib.hxx
Armin Le Grand (allotropia) ab7c81f556 ITEM: Get away from classic 'poolable' Item flag
To understand this, some look back in history will be needed to see
why it is as it is today. In some (reworked) comments 'poolable' is
described as flag to hold Items in the ItemPool, also always having
only one incarnation of each possible Item.
This is not the original intention, but a side-effect. The reason is
what the binary format in the office did: To save a document, the
Objects & the Pool were saved, *not* individual Items *together*
with the objects. The Pool was completely (binary) saved (and loaded)
in one run.
Temporary IDs were used to represent at the objects in file which
Items were referenced. This *required* to have only one incarnation
per item to have a minimal binary file size, thus this high effort
was put into this. At doc load, the pool was loaded, all Items were
set to RefCount 5000, the references from the objects were restored
and then for each Item the RefCount was lowered by 5000 again
and - if being zero - deleted. Items for UI were marked 'non-poolable'
to *not* safe them with the document, so poolable was a flag to decide
if that Info/Item was to be saved with the document - or more direct:
if it is Model Data.
Items are small, so if we prefer runtime it is okay to no longer being
strict with this, anyways does not happen often and has only marginal
memory effects - compared to runtime effects/savings.
Other problems which this caused: One example is that objects in the
UNDO stack were still in the pool, so e.g. deleted pictures were saved
with the document despite no longer being used (!). That is the reason
we have an UndoItemPool and a method MigrateItemPool to move stuff to
that Pool when objects go to the UNDO stack - all of this is also no
longer needed.
Cleaning this up means to ideally have all items in the SfxItemSet,
no longer at the Pool. The Pool should be reduced to a 'Default-Item-
Holder' and a 'Slot-to-whichId-mapper'.

This needs thorough cleanups/removals, but will be worth it because
that massive simplification(s) will increase safety an runtime and make
migrating to the goal of completely type-based ItemSet stuff easier for
the future. Hopefully only view code in the office working with items
will have to be changed for this.

In this 1st step I already found that some 'compromizes' will be
needed:
- There are still Items that have to be at the pool to make the
Surrogate-stuff working. This gives back all Items in a Pool of a type
and is used in ca. 80 cases. Each one looks at these Items *without*
context (e.g. a SfxItemSet at an Object would be a context), so if e.g.
a dialog is open that temporarily uses Items of that type you would
also get these - without knowing about it...
To make that work there is still a mechanism to have Items at the Pool,
but now just *registering* (and un-reg) them without any sort/search/
remove needs. Also only for Items that need that, so I evaluated the
GetItemSurrogates calls and added some asserts when GetItemSurrogates
tries to access an unregistered item type which needs to be added.

- Another caveat is that there are about 250 places that directly put
Items to the Pool (not all remove these, that is done at pool deletion,
so some kind of silent 'garbage-collection' is in place). To have an
overview I renamed the accessing methods to separate them from the same
functionality at the SfxItemSet, which had the same names. An
implementation does still add these directly to the pool, there is no
way to cleanup those usages for now. In principle all these should be
changed to hold the data at an SfxItemSet.

I am still hunting problems. But you can build the office, all apps
work (including chart) and you can do speed comparisons already.

There are test throwing errors, so I hunt these now. It is hard to
give an estimation about how much more changes/corrections will be
needed.

Completed adaptions to new registered Items at Pool, that reduces the
failing tests. Still many that I need to hunt.

Added stuff to work around that 'compromize' in ScDocumentPool: It
overloads ::PutImpl of the pool to implement special handling for
a single Item in SC, the ScPatternAttr. In former code that method
was used from SfxItemSet and ::PutImpl at the pool directly, so it
was only used in one place. I am not sure if it was used from
the SfxItemSet functionality, but better offer it for now. To not
waste too much runtime the callbacks depend on the boolean
'NewItemCallback' at the SfxPoolItem, it gets set for that single
Item in SC and only then the callbacks trigger. I hope to get rid
of those again, e.g. newItem_UseDirect is only needed since we have
no 'real' StaticPoolDefaults currently - another thing that needs to
be cleaned up in a next step.

Since usages of impl(Create|Cleanup)ItemEntry and
Direct(Put|Remove)ItemInPoolImpl got more and more similar I decided to
unify that: move impl(Create|Cleanup)ItemEntry to tooling, make it
globally available in svl and use it also directly for
Direct(Put|Remove)ItemInPoolImpl. This slightly increases the failing
tests again, but only since in Direct(Put|Remove)ItemInPoolImpl that
fallback (e.g. tryToGetEqualItem) was used before, thus this is the
same class of errors (SfxPoolItem ptr-compare) as the others which I
will need to find anyways. Also fixed some missing stuff.

Have now idenified and redirected all SfxPoolItem ptr-compares
to be able to debug these - one cause for the remaining errors is
probably that before with bPoolable those often were sufficient, but
are no longer. Used the [loplugin:itemcompare] and a local clang
build to do so, see https://gerrit.libreoffice.org/c/core/+/157172

Stabilized Direct(Put|Remove)ItemInPoolImpl forwards, added parameter
to implCreateItemEntry to signal that it gets called from DirectPool
stuff - currently needed. Hopefully when getting rid of that DirectPool
stuff we can remove that again

Added two more debug functionalities:
- Added a SerialNumber to allow targeted debugging for deterministic
  cases
- Added registering & listing of still-allocated SfxPoolItems at
  office shutdown

Found PtrComp error in thints.cxx - POC, thanks to
areSfxPoolItemPtrsEqual. Will hopefully help more with other tests

Found some wrong asserts/warnings where I was too careful and not
finding something/succeeding is OK, fixes some UnitTests for SC

For SC I now just tried to replace all areSfxPoolItemPtrsEqual with
the full-ptr-content compare SfxPoolItem::areSame. I also needed to
experiment/adapt the newItem_Callback solution but got it working.

Did that replacement now for SW too, found some places where the
direct ptr compare is OK.

Continued for the rest of occurrences, now all 160 places evaluated.
Also done some cleanups.

Massive cleanups of stuff no longer needed with this paradigm change.
Also decided to keep tryToGetEqualItem/ITEM_CLASSIC_MODE for now.
It is used for *one* Item (ScPatternAttr/ATTR_PATTERN) in SC that
already needs many exceptions. Also useful for testing if errors
come up on this change to test if it is related to this.

Added forwarding of target Pool for ::Clone in SvxSetItem and
SvxSetItem, simplified SfxStateCache::SetState_Impl and returned
to simple ptr compares in SfxPoolItem::areSame to not do the test
in areSfxPoolItemPtrsEqual.

Debugged through UITest_calc_tests9 and found that in tdf133629
where BoxStyle is applied to fully selected empty calc the Item-
reuse fallback has to be used not only for ATTR_PATTERN, see
comment @implCreateItemEntry. Maybe more...

Problem with test_tdf156611_insert_hyperlink_like_excel. Found that
in ScEditShell::GetFirstURLFieldFromCell the correct SvxURLField
is found and returned as ptr, but it's usage crashes. That is due to
the SfxItemSet aEditSet used there gets destroyed at function return
what again deletes the SvxFieldItem that is holding the SvxURLField
that gets returned.
This shows a more general problem: There is no 'SfxPoolItemHolder'
that safely holds a single SfxPoolItem - like a SfxItemSet for a
single Item (if Items would be shared_ptrs, that would be a safe
return value).
That will be needed in the future, but for now use another solution:
Since I see no reason why EE_FEATURE_FIELD should not be shareable
I wil change this for ow in the SfxItemInfo for EditCharAttribField.
That way the Item returned will be shared (RefCnt > 1) and thus not
be deleted.

I changed the return value for GetURLField() and
GetFirstURLFieldFromCell() in ScEditShell: At least for
GetFirstURLFieldFromCell the return type/value was not safe: The
SvxFieldItem accessed there and held in the local temporary
SfxItemSet may be deleted with it, so return value can be
corrupted/deleted. To avoid that, return a Clone of SvxFieldData
as a unique_ptr.

With all that UnitTest debugging and hunting and to get the paradigm
change working to no longer rely on shared/pooled items I lost a
little bit focus on speed, so I made an optimization round for the
two central methods implCreateItemEntry/implCleanupItemEntry to
get back to the speed improvements that I detected when starting this
change. It was mainly lost due to that 'strange' chained pool stuff
we have, so I added to detect the target pool (the one at which the
WhichID is registered) directly and only once. Next thing to cleanup
will/should be the pool and it's concept, all this is not needed
and really costs runtime.
Since implCreateItemEntry/implCleanupItemEntry are executed millions
of times, each cycle counts here.

Had an error in the last changes: pool::*_Impl methods use index
instead of WhichID - most of them. Another bad trap, I really need
to cleanup pool stuff next.

Change-Id: I6295f332325b33268ec396ed46f8d0a1026e2d69
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157559
Tested-by: Jenkins
Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
2023-11-07 18:07:13 +01:00

365 lines
15 KiB
C++

/* -*- 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 .
*/
#pragma once
#include <memory>
#include <svl/poolitem.hxx>
#include <svl/intitem.hxx>
#include <svl/eitem.hxx>
#include <svx/sdangitm.hxx>
#include <o3tl/sorted_vector.hxx>
#include <o3tl/typed_flags_set.hxx>
#include "scdllapi.h"
#include "global.hxx"
// flags for cells hidden by merge
// and control for auto filter
enum class ScMF {
NONE = 0x0000,
Hor = 0x0001,
Ver = 0x0002,
Auto = 0x0004, /// autofilter arrow
Button = 0x0008, /// field button for datapilot
Scenario = 0x0010,
ButtonPopup = 0x0020, /// dp button with popup arrow
HiddenMember = 0x0040, /// dp field button with presence of hidden member
DpTable = 0x0080, /// dp table output
DpCollapse = 0x0100, /// dp compact layout collapse button
DpExpand = 0x0200, /// dp compact layout expand button
ButtonPopup2 = 0x0400, /// dp button with popup arrow for multiple fields
All = 0x07FF
};
namespace o3tl {
template<> struct typed_flags<ScMF> : is_typed_flags<ScMF, 0x07ff> {};
}
class EditTextObject;
namespace editeng { class SvxBorderLine; }
bool SC_DLLPUBLIC ScHasPriority( const ::editeng::SvxBorderLine* pThis, const ::editeng::SvxBorderLine* pOther );
class SC_DLLPUBLIC ScMergeAttr final : public SfxPoolItem
{
SCCOL nColMerge;
SCROW nRowMerge;
public:
ScMergeAttr();
ScMergeAttr( SCCOL nCol, SCROW nRow );
ScMergeAttr( const ScMergeAttr& );
virtual ~ScMergeAttr() override;
virtual bool operator==( const SfxPoolItem& ) const override;
virtual ScMergeAttr* Clone( SfxItemPool *pPool = nullptr ) const override;
SCCOL GetColMerge() const {return nColMerge; }
SCROW GetRowMerge() const {return nRowMerge; }
bool IsMerged() const { return nColMerge>1 || nRowMerge>1; }
ScMergeAttr& operator=(const ScMergeAttr& rMerge)
{
nColMerge = rMerge.nColMerge;
nRowMerge = rMerge.nRowMerge;
return *this;
}
virtual void dumpAsXml(xmlTextWriterPtr pWriter) const override;
};
class SC_DLLPUBLIC ScMergeFlagAttr final : public SfxInt16Item
{
public:
ScMergeFlagAttr();
ScMergeFlagAttr(ScMF nFlags);
virtual ~ScMergeFlagAttr() override;
ScMergeFlagAttr(ScMergeFlagAttr const &) = default;
ScMergeFlagAttr(ScMergeFlagAttr &&) = default;
ScMergeFlagAttr & operator =(ScMergeFlagAttr const &) = delete; // due to SfxInt16Item
ScMergeFlagAttr & operator =(ScMergeFlagAttr &&) = delete; // due to SfxInt16Item
ScMergeFlagAttr* Clone(SfxItemPool * pPool = nullptr) const override;
ScMF GetValue() const { return static_cast<ScMF>(SfxInt16Item::GetValue()); }
bool IsHorOverlapped() const { return bool( GetValue() & ScMF::Hor ); }
bool IsVerOverlapped() const { return bool( GetValue() & ScMF::Ver ); }
bool IsOverlapped() const { return bool( GetValue() & ( ScMF::Hor | ScMF::Ver ) ); }
bool HasAutoFilter() const { return bool( GetValue() & ScMF::Auto ); }
bool IsScenario() const { return bool( GetValue() & ScMF::Scenario ); }
bool HasPivotButton() const;
bool HasPivotPopupButton() const;
bool HasPivotToggle() const;
bool HasPivotMultiFieldPopupButton() const;
virtual void dumpAsXml(xmlTextWriterPtr pWriter) const override;
};
class SC_DLLPUBLIC ScProtectionAttr final : public SfxPoolItem
{
bool bProtection; ///< protect cell
bool bHideFormula; ///< hide formula
bool bHideCell; ///< hide cell
bool bHidePrint; ///< don't print cell
public:
static SfxPoolItem* CreateDefault();
ScProtectionAttr();
ScProtectionAttr( bool bProtect,
bool bHFormula = false,
bool bHCell = false,
bool bHPrint = false);
ScProtectionAttr( const ScProtectionAttr& );
virtual ~ScProtectionAttr() override;
OUString GetValueText() const;
virtual bool GetPresentation(
SfxItemPresentation ePres,
MapUnit eCoreMetric,
MapUnit ePresMetric,
OUString& rText,
const IntlWrapper& rIntl ) const override;
virtual bool operator==( const SfxPoolItem& ) const override;
virtual ScProtectionAttr* Clone( SfxItemPool *pPool = nullptr ) const override;
virtual bool QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId = 0 ) const override;
virtual bool PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId ) override;
bool GetProtection() const { return bProtection; }
void SetProtection( bool bProtect);
bool GetHideFormula() const { return bHideFormula; }
void SetHideFormula( bool bHFormula);
bool GetHideCell() const { return bHideCell; }
void SetHideCell( bool bHCell);
bool GetHidePrint() const { return bHidePrint; }
void SetHidePrint( bool bHPrint);
ScProtectionAttr& operator=(const ScProtectionAttr& rProtection)
{
bProtection = rProtection.bProtection;
bHideFormula = rProtection.bHideFormula;
bHideCell = rProtection.bHideCell;
bHidePrint = rProtection.bHidePrint;
return *this;
}
virtual void dumpAsXml(xmlTextWriterPtr pWriter) const override;
};
// page format item: contents of header and footer
#define SC_HF_LEFTAREA 1
#define SC_HF_CENTERAREA 2
#define SC_HF_RIGHTAREA 3
class SC_DLLPUBLIC ScPageHFItem final : public SfxPoolItem
{
std::unique_ptr<EditTextObject> pLeftArea;
std::unique_ptr<EditTextObject> pCenterArea;
std::unique_ptr<EditTextObject> pRightArea;
public:
ScPageHFItem( sal_uInt16 nWhich );
ScPageHFItem( const ScPageHFItem& rItem );
virtual ~ScPageHFItem() override;
virtual bool operator==( const SfxPoolItem& ) const override;
virtual ScPageHFItem* Clone( SfxItemPool *pPool = nullptr ) const override;
virtual bool QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId = 0 ) const override;
virtual bool PutValue( const css::uno::Any& rVal, sal_uInt8 nMemberId ) override;
const EditTextObject* GetLeftArea() const { return pLeftArea.get(); }
const EditTextObject* GetCenterArea() const { return pCenterArea.get(); }
const EditTextObject* GetRightArea() const { return pRightArea.get(); }
void SetLeftArea( const EditTextObject& rNew );
void SetCenterArea( const EditTextObject& rNew );
void SetRightArea( const EditTextObject& rNew );
virtual void dumpAsXml(xmlTextWriterPtr pWriter) const override;
};
// page format item: contents of header and footer
class SC_DLLPUBLIC ScViewObjectModeItem final : public SfxEnumItem<ScVObjMode>
{
public:
ScViewObjectModeItem( sal_uInt16 nWhich );
ScViewObjectModeItem( sal_uInt16 nWhich, ScVObjMode eMode );
virtual ~ScViewObjectModeItem() override;
ScViewObjectModeItem(ScViewObjectModeItem const &) = default;
ScViewObjectModeItem(ScViewObjectModeItem &&) = default;
ScViewObjectModeItem & operator =(ScViewObjectModeItem const &) = delete; // due to SfxEnumItem<ScVObjMode>
ScViewObjectModeItem & operator =(ScViewObjectModeItem &&) = delete; // due to SfxEnumItem<ScVObjMode>
virtual sal_uInt16 GetValueCount() const override;
virtual ScViewObjectModeItem* Clone( SfxItemPool *pPool = nullptr ) const override;
virtual bool GetPresentation( SfxItemPresentation ePres,
MapUnit eCoreMetric,
MapUnit ePresMetric,
OUString& rText,
const IntlWrapper& rIntl ) const override;
};
/** Member ID for "page scale to width" value in QueryValue() and PutValue(). */
const sal_uInt8 SC_MID_PAGE_SCALETO_WIDTH = 1;
/** Member ID for "page scale to height" value in QueryValue() and PutValue(). */
const sal_uInt8 SC_MID_PAGE_SCALETO_HEIGHT = 2;
/** Contains the "scale to width/height" attribute in page styles. */
class SC_DLLPUBLIC ScPageScaleToItem final : public SfxPoolItem
{
public:
/** Default c'tor sets the width and height to 0. */
explicit ScPageScaleToItem();
explicit ScPageScaleToItem( sal_uInt16 nWidth, sal_uInt16 nHeight );
virtual ~ScPageScaleToItem() override;
ScPageScaleToItem(ScPageScaleToItem const &) = default;
ScPageScaleToItem(ScPageScaleToItem &&) = default;
ScPageScaleToItem & operator =(ScPageScaleToItem const &) = delete; // due to SfxPoolItem
ScPageScaleToItem & operator =(ScPageScaleToItem &&) = delete; // due to SfxPoolItem
virtual ScPageScaleToItem* Clone( SfxItemPool* = nullptr ) const override;
virtual bool operator==( const SfxPoolItem& rCmp ) const override;
sal_uInt16 GetWidth() const { return mnWidth; }
sal_uInt16 GetHeight() const { return mnHeight; }
bool IsValid() const { return mnWidth || mnHeight; }
void SetWidth( sal_uInt16 nWidth ) { mnWidth = nWidth; }
void SetHeight( sal_uInt16 nHeight ) { mnHeight = nHeight; }
void Set( sal_uInt16 nWidth, sal_uInt16 nHeight )
{ mnWidth = nWidth; mnHeight = nHeight; }
virtual bool GetPresentation( SfxItemPresentation ePresentation,
MapUnit, MapUnit,
OUString& rText,
const IntlWrapper& ) const override;
virtual bool QueryValue( css::uno::Any& rAny, sal_uInt8 nMemberId = 0 ) const override;
virtual bool PutValue( const css::uno::Any& rAny, sal_uInt8 nMemberId ) override;
virtual void dumpAsXml(xmlTextWriterPtr pWriter) const override;
private:
sal_uInt16 mnWidth;
sal_uInt16 mnHeight;
};
typedef o3tl::sorted_vector<sal_uInt32> ScCondFormatIndexes;
class SAL_DLLPUBLIC_RTTI ScCondFormatItem final : public SfxPoolItem
{
public:
explicit ScCondFormatItem();
explicit ScCondFormatItem(sal_uInt32 nIndex);
explicit ScCondFormatItem(const ScCondFormatIndexes& );
explicit ScCondFormatItem(ScCondFormatIndexes&&) noexcept;
virtual ~ScCondFormatItem() override;
virtual bool operator==(const SfxPoolItem& rCmp ) const override;
virtual ScCondFormatItem* Clone( SfxItemPool* = nullptr ) const override;
const ScCondFormatIndexes& GetCondFormatData() const { return maIndex;}
virtual void dumpAsXml(xmlTextWriterPtr pWriter) const override;
private:
ScCondFormatIndexes maIndex;
};
class SC_DLLPUBLIC ScRotateValueItem final : public SdrAngleItem
{
public:
ScRotateValueItem(Degree100 nAngle);
virtual ScRotateValueItem* Clone(SfxItemPool* pPool=nullptr) const override;
virtual bool GetPresentation( SfxItemPresentation ePresentation,
MapUnit, MapUnit,
OUString& rText,
const IntlWrapper& rIntl) const override;
};
class SC_DLLPUBLIC ScShrinkToFitCell final : public SfxBoolItem
{
public:
ScShrinkToFitCell(bool bShrink = false);
virtual ScShrinkToFitCell* Clone(SfxItemPool *pPool = nullptr) const override;
virtual bool GetPresentation(SfxItemPresentation ePres,
MapUnit eCoreMetric,
MapUnit ePresMetric,
OUString &rText,
const IntlWrapper& rIntl) const override;
};
class SC_DLLPUBLIC ScVerticalStackCell final : public SfxBoolItem
{
public:
ScVerticalStackCell(bool bStack = false);
virtual ScVerticalStackCell* Clone(SfxItemPool *pPool = nullptr) const override;
virtual bool GetPresentation(SfxItemPresentation ePres,
MapUnit eCoreMetric,
MapUnit ePresMetric,
OUString &rText,
const IntlWrapper& rIntl) const override;
};
class SC_DLLPUBLIC ScLineBreakCell final : public SfxBoolItem
{
public:
ScLineBreakCell(bool bLineBreak = false);
virtual ScLineBreakCell* Clone(SfxItemPool *pPool = nullptr) const override;
virtual bool GetPresentation(SfxItemPresentation ePres,
MapUnit eCoreMetric,
MapUnit ePresMetric,
OUString &rText,
const IntlWrapper& rIntl) const override;
};
class ScHyphenateCell final : public SfxBoolItem
{
public:
ScHyphenateCell(bool bHyphenate= false);
virtual ScHyphenateCell* Clone(SfxItemPool *pPool = nullptr) const override;
virtual bool GetPresentation(SfxItemPresentation ePres,
MapUnit eCoreMetric,
MapUnit ePresMetric,
OUString &rText,
const IntlWrapper& rIntl) const override;
};
class SC_DLLPUBLIC ScIndentItem final : public SfxUInt16Item
{
public:
ScIndentItem(sal_uInt16 nIndent = 0);
virtual ScIndentItem* Clone(SfxItemPool* pPool=nullptr) const override;
virtual bool GetPresentation( SfxItemPresentation ePresentation,
MapUnit, MapUnit,
OUString& rText,
const IntlWrapper& rIntl) const override;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */