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>
diff --git a/chart2/source/view/main/ChartItemPool.cxx b/chart2/source/view/main/ChartItemPool.cxx
index ed62e57..8f787cd 100644
--- a/chart2/source/view/main/ChartItemPool.cxx
+++ b/chart2/source/view/main/ChartItemPool.cxx
@@ -190,8 +190,10 @@ ChartItemPool::ChartItemPool():
    const sal_uInt16 nMax = SCHATTR_END - SCHATTR_START + 1;
    for( sal_uInt16 i = 0; i < nMax; i++ )
    {
        // _nSID, _bNeedsPoolRegistration, _bShareable
        pItemInfos[i]._nSID = 0;
        pItemInfos[i]._bPoolable = true;
        pItemInfos[i]._bNeedsPoolRegistration = false;
        pItemInfos[i]._bShareable = true;
    }

    // slot ids differing from which ids
diff --git a/cui/source/tabpages/tabarea.cxx b/cui/source/tabpages/tabarea.cxx
index 9b08268..4b50b74 100644
--- a/cui/source/tabpages/tabarea.cxx
+++ b/cui/source/tabpages/tabarea.cxx
@@ -83,7 +83,7 @@ void SvxAreaTabDialog::SavePalettes()
        if ( pShell )
            pShell->PutItem( aColorListItem );
        else
            mpDrawModel->GetItemPool().Put(aColorListItem,SID_COLOR_TABLE);
            mpDrawModel->GetItemPool().DirectPutItemInPool(aColorListItem,SID_COLOR_TABLE);
        mpColorList = mpDrawModel->GetColorList();
    }
    if( mpNewGradientList != mpDrawModel->GetGradientList() )
@@ -93,7 +93,7 @@ void SvxAreaTabDialog::SavePalettes()
        if ( pShell )
            pShell->PutItem( aItem );
        else
            mpDrawModel->GetItemPool().Put(aItem,SID_GRADIENT_LIST);
            mpDrawModel->GetItemPool().DirectPutItemInPool(aItem,SID_GRADIENT_LIST);
        mpGradientList = mpDrawModel->GetGradientList();
    }
    if( mpNewHatchingList != mpDrawModel->GetHatchList() )
@@ -103,7 +103,7 @@ void SvxAreaTabDialog::SavePalettes()
        if ( pShell )
            pShell->PutItem( aItem );
        else
            mpDrawModel->GetItemPool().Put(aItem,SID_HATCH_LIST);
            mpDrawModel->GetItemPool().DirectPutItemInPool(aItem,SID_HATCH_LIST);
        mpHatchingList = mpDrawModel->GetHatchList();
    }
    if( mpNewBitmapList != mpDrawModel->GetBitmapList() )
@@ -113,7 +113,7 @@ void SvxAreaTabDialog::SavePalettes()
        if ( pShell )
            pShell->PutItem( aItem );
        else
            mpDrawModel->GetItemPool().Put(aItem,SID_BITMAP_LIST);
            mpDrawModel->GetItemPool().DirectPutItemInPool(aItem,SID_BITMAP_LIST);
        mpBitmapList = mpDrawModel->GetBitmapList();
    }
    if( mpNewPatternList != mpDrawModel->GetPatternList() )
@@ -123,7 +123,7 @@ void SvxAreaTabDialog::SavePalettes()
        if( pShell )
            pShell->PutItem( aItem );
        else
            mpDrawModel->GetItemPool().Put(aItem,SID_PATTERN_LIST);
            mpDrawModel->GetItemPool().DirectPutItemInPool(aItem,SID_PATTERN_LIST);
        mpPatternList = mpDrawModel->GetPatternList();
    }

@@ -148,7 +148,7 @@ void SvxAreaTabDialog::SavePalettes()
        if ( pShell )
            pShell->PutItem( aItem );
        else
            mpDrawModel->GetItemPool().Put(aItem);
            mpDrawModel->GetItemPool().DirectPutItemInPool(aItem);
    }

    if( mnBitmapListState & ChangeType::MODIFIED )
@@ -162,7 +162,7 @@ void SvxAreaTabDialog::SavePalettes()
            pShell->PutItem( aItem );
        else
        {
            mpDrawModel->GetItemPool().Put(aItem);
            mpDrawModel->GetItemPool().DirectPutItemInPool(aItem);
        }
    }

@@ -176,7 +176,7 @@ void SvxAreaTabDialog::SavePalettes()
        if( pShell )
            pShell->PutItem( aItem );
        else
            mpDrawModel->GetItemPool().Put(aItem);
            mpDrawModel->GetItemPool().DirectPutItemInPool(aItem);
    }

    if( mnGradientListState & ChangeType::MODIFIED )
@@ -190,7 +190,7 @@ void SvxAreaTabDialog::SavePalettes()
            pShell->PutItem( aItem );
        else
        {
            mpDrawModel->GetItemPool().Put(aItem);
            mpDrawModel->GetItemPool().DirectPutItemInPool(aItem);
        }
    }

@@ -202,7 +202,7 @@ void SvxAreaTabDialog::SavePalettes()
            pShell->PutItem( aItem );
        else
        {
            mpDrawModel->GetItemPool().Put(aItem);
            mpDrawModel->GetItemPool().DirectPutItemInPool(aItem);
        }
    }
}
diff --git a/dbaccess/source/ui/dlg/dbadmin.cxx b/dbaccess/source/ui/dlg/dbadmin.cxx
index 95bc34e..372e72e 100644
--- a/dbaccess/source/ui/dlg/dbadmin.cxx
+++ b/dbaccess/source/ui/dlg/dbadmin.cxx
@@ -340,67 +340,68 @@ void ODbAdminDialog::createItemSet(std::unique_ptr<SfxItemSet>& _rpSet, rtl::Ref
    // create the pool
    static SfxItemInfo const aItemInfos[DSID_LAST_ITEM_ID - DSID_FIRST_ITEM_ID + 1] =
    {
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        {0,false},
        // _nSID, _bNeedsPoolRegistration, _bShareable
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
        {0,false,false},
    };

    OSL_ENSURE(std::size(aItemInfos) == sal_uInt16(DSID_LAST_ITEM_ID),"Invalid Ids!");
diff --git a/dbaccess/source/ui/misc/UITools.cxx b/dbaccess/source/ui/misc/UITools.cxx
index ae856a3..a07d588 100644
--- a/dbaccess/source/ui/misc/UITools.cxx
+++ b/dbaccess/source/ui/misc/UITools.cxx
@@ -763,11 +763,12 @@ bool callColumnFormatDialog(weld::Widget* _pParent,
    // UNO->ItemSet
    static SfxItemInfo aItemInfos[] =
    {
        { 0, false },
        { SID_ATTR_NUMBERFORMAT_VALUE,      true },
        { SID_ATTR_ALIGN_HOR_JUSTIFY,       true },
        { SID_ATTR_NUMBERFORMAT_INFO,       true },
        { SID_ATTR_NUMBERFORMAT_ONE_AREA,   true }
        // _nSID, _bNeedsPoolRegistration, _bShareable
        { 0,                                false, true },    // SBA_DEF_RANGEFORMAT
        { SID_ATTR_NUMBERFORMAT_VALUE,      false, true },    // SBA_DEF_FMTVALUE
        { SID_ATTR_ALIGN_HOR_JUSTIFY,       false, true },    // SBA_ATTR_ALIGN_HOR_JUSTIFY
        { SID_ATTR_NUMBERFORMAT_INFO,       false, true },    // SID_ATTR_NUMBERFORMAT_INFO
        { SID_ATTR_NUMBERFORMAT_ONE_AREA,   false, true }     // SID_ATTR_NUMBERFORMAT_ONE_AREA
    };
    static const auto aAttrMap = svl::Items<
        SBA_DEF_RANGEFORMAT, SBA_ATTR_ALIGN_HOR_JUSTIFY,
diff --git a/editeng/source/editeng/editdoc.cxx b/editeng/source/editeng/editdoc.cxx
index 9b0d394..9841d78 100644
--- a/editeng/source/editeng/editdoc.cxx
+++ b/editeng/source/editeng/editdoc.cxx
@@ -157,70 +157,72 @@ bool IsScriptItemValid( sal_uInt16 nItemId, short nScriptType )
    return bValid;
}

const SfxItemInfo aItemInfos[EDITITEMCOUNT] = {
        { SID_ATTR_FRAMEDIRECTION, true },         // EE_PARA_WRITINGDIR
        { 0, true },                               // EE_PARA_XMLATTRIBS
        { SID_ATTR_PARA_HANGPUNCTUATION, true },   // EE_PARA_HANGINGPUNCTUATION
        { SID_ATTR_PARA_FORBIDDEN_RULES, true },   // EE_PARA_FORBIDDENRULES
        { SID_ATTR_PARA_SCRIPTSPACE, true },       // EE_PARA_ASIANCJKSPACING
        { SID_ATTR_NUMBERING_RULE, true },         // EE_PARA_NUMBULL
        { 0, true },                               // EE_PARA_HYPHENATE
        { 0, true },                               // EE_PARA_HYPHENATE_NO_CAPS
        { 0, true },                               // EE_PARA_HYPHENATE_NO_LAST_WORD
        { 0, true },                               // EE_PARA_BULLETSTATE
        { 0, true },                               // EE_PARA_OUTLLRSPACE
        { SID_ATTR_PARA_OUTLLEVEL, true },         // EE_PARA_OUTLLEVEL
        { SID_ATTR_PARA_BULLET, true },            // EE_PARA_BULLET
        { SID_ATTR_LRSPACE, true },                // EE_PARA_LRSPACE
        { SID_ATTR_ULSPACE, true },                // EE_PARA_ULSPACE
        { SID_ATTR_PARA_LINESPACE, true },         // EE_PARA_SBL
        { SID_ATTR_PARA_ADJUST, true },            // EE_PARA_JUST
        { SID_ATTR_TABSTOP, true },                // EE_PARA_TABS
        { SID_ATTR_ALIGN_HOR_JUSTIFY_METHOD, true }, // EE_PARA_JUST_METHOD
        { SID_ATTR_ALIGN_VER_JUSTIFY, true },      // EE_PARA_VER_JUST
        { SID_ATTR_CHAR_COLOR, true },         // EE_CHAR_COLOR
        { SID_ATTR_CHAR_FONT, true },          // EE_CHAR_FONTINFO
        { SID_ATTR_CHAR_FONTHEIGHT, true },    // EE_CHAR_FONTHEIGHT
        { SID_ATTR_CHAR_SCALEWIDTH, true },    // EE_CHAR_FONTWIDTH
        { SID_ATTR_CHAR_WEIGHT, true },        // EE_CHAR_WEIGHT
        { SID_ATTR_CHAR_UNDERLINE, true },     // EE_CHAR_UNDERLINE
        { SID_ATTR_CHAR_STRIKEOUT, true },     // EE_CHAR_STRIKEOUT
        { SID_ATTR_CHAR_POSTURE, true },       // EE_CHAR_ITALIC
        { SID_ATTR_CHAR_CONTOUR, true },       // EE_CHAR_OUTLINE
        { SID_ATTR_CHAR_SHADOWED, true },      // EE_CHAR_SHADOW
        { SID_ATTR_CHAR_ESCAPEMENT, true },    // EE_CHAR_ESCAPEMENT
        { SID_ATTR_CHAR_AUTOKERN, true },      // EE_CHAR_PAIRKERNING
        { SID_ATTR_CHAR_KERNING, true },       // EE_CHAR_KERNING
        { SID_ATTR_CHAR_WORDLINEMODE, true },  // EE_CHAR_WLM
        { SID_ATTR_CHAR_LANGUAGE, true },      // EE_CHAR_LANGUAGE
        { SID_ATTR_CHAR_CJK_LANGUAGE, true },  // EE_CHAR_LANGUAGE_CJK
        { SID_ATTR_CHAR_CTL_LANGUAGE, true },  // EE_CHAR_LANGUAGE_CTL
        { SID_ATTR_CHAR_CJK_FONT, true },      // EE_CHAR_FONTINFO_CJK
        { SID_ATTR_CHAR_CTL_FONT, true },      // EE_CHAR_FONTINFO_CTL
        { SID_ATTR_CHAR_CJK_FONTHEIGHT, true }, // EE_CHAR_FONTHEIGHT_CJK
        { SID_ATTR_CHAR_CTL_FONTHEIGHT, true }, // EE_CHAR_FONTHEIGHT_CTL
        { SID_ATTR_CHAR_CJK_WEIGHT, true },    // EE_CHAR_WEIGHT_CJK
        { SID_ATTR_CHAR_CTL_WEIGHT, true },    // EE_CHAR_WEIGHT_CTL
        { SID_ATTR_CHAR_CJK_POSTURE, true },   // EE_CHAR_ITALIC_CJK
        { SID_ATTR_CHAR_CTL_POSTURE, true },   // EE_CHAR_ITALIC_CTL
        { SID_ATTR_CHAR_EMPHASISMARK, true },  // EE_CHAR_EMPHASISMARK
        { SID_ATTR_CHAR_RELIEF, true },        // EE_CHAR_RELIEF
        { 0, true },                           // EE_CHAR_RUBI_DUMMY
        { 0, true },                           // EE_CHAR_XMLATTRIBS
        { SID_ATTR_CHAR_OVERLINE, true },      // EE_CHAR_OVERLINE
        { SID_ATTR_CHAR_CASEMAP, true },       // EE_CHAR_CASEMAP
        { SID_ATTR_CHAR_GRABBAG, true },       // EE_CHAR_GRABBAG
        { SID_ATTR_CHAR_BACK_COLOR, true },    // EE_CHAR_BKGCOLOR
        { 0, true },                           // EE_FEATURE_TAB
        { 0, true },                           // EE_FEATURE_LINEBR
        { SID_ATTR_CHAR_CHARSETCOLOR, true },  // EE_FEATURE_NOTCONV
        { SID_FIELD, false },                  // EE_FEATURE_FIELD
const SfxItemInfo aItemInfos[EDITITEMCOUNT] =
{
        // _nSID, _bNeedsPoolRegistration, _bShareable
        { SID_ATTR_FRAMEDIRECTION, false, true },         // EE_PARA_WRITINGDIR
        { 0, true, true },                               // EE_PARA_XMLATTRIBS
        { SID_ATTR_PARA_HANGPUNCTUATION, false, true },   // EE_PARA_HANGINGPUNCTUATION
        { SID_ATTR_PARA_FORBIDDEN_RULES, false, true },   // EE_PARA_FORBIDDENRULES
        { SID_ATTR_PARA_SCRIPTSPACE, false, true },       // EE_PARA_ASIANCJKSPACING
        { SID_ATTR_NUMBERING_RULE, false, true },         // EE_PARA_NUMBULL
        { 0, false, true },                               // EE_PARA_HYPHENATE
        { 0, false, true },                               // EE_PARA_HYPHENATE_NO_CAPS
        { 0, false, true },                               // EE_PARA_HYPHENATE_NO_LAST_WORD
        { 0, false, true },                               // EE_PARA_BULLETSTATE
        { 0, false, true },                               // EE_PARA_OUTLLRSPACE
        { SID_ATTR_PARA_OUTLLEVEL, false, true },         // EE_PARA_OUTLLEVEL
        { SID_ATTR_PARA_BULLET, false, true },            // EE_PARA_BULLET
        { SID_ATTR_LRSPACE, false, true },                // EE_PARA_LRSPACE
        { SID_ATTR_ULSPACE, false, true },                // EE_PARA_ULSPACE
        { SID_ATTR_PARA_LINESPACE, false, true },         // EE_PARA_SBL
        { SID_ATTR_PARA_ADJUST, false, true },            // EE_PARA_JUST
        { SID_ATTR_TABSTOP, false, true },                // EE_PARA_TABS
        { SID_ATTR_ALIGN_HOR_JUSTIFY_METHOD, false, true }, // EE_PARA_JUST_METHOD
        { SID_ATTR_ALIGN_VER_JUSTIFY, false, true },      // EE_PARA_VER_JUST
        { SID_ATTR_CHAR_COLOR, true, true },         // EE_CHAR_COLOR
        { SID_ATTR_CHAR_FONT, true, true },          // EE_CHAR_FONTINFO
        { SID_ATTR_CHAR_FONTHEIGHT, false, true },    // EE_CHAR_FONTHEIGHT
        { SID_ATTR_CHAR_SCALEWIDTH, false, true },    // EE_CHAR_FONTWIDTH
        { SID_ATTR_CHAR_WEIGHT, false, true },        // EE_CHAR_WEIGHT
        { SID_ATTR_CHAR_UNDERLINE, false, true },     // EE_CHAR_UNDERLINE
        { SID_ATTR_CHAR_STRIKEOUT, false, true },     // EE_CHAR_STRIKEOUT
        { SID_ATTR_CHAR_POSTURE, false, true },       // EE_CHAR_ITALIC
        { SID_ATTR_CHAR_CONTOUR, false, true },       // EE_CHAR_OUTLINE
        { SID_ATTR_CHAR_SHADOWED, false, true },      // EE_CHAR_SHADOW
        { SID_ATTR_CHAR_ESCAPEMENT, false, true },    // EE_CHAR_ESCAPEMENT
        { SID_ATTR_CHAR_AUTOKERN, false, true },      // EE_CHAR_PAIRKERNING
        { SID_ATTR_CHAR_KERNING, false, true },       // EE_CHAR_KERNING
        { SID_ATTR_CHAR_WORDLINEMODE, false, true },  // EE_CHAR_WLM
        { SID_ATTR_CHAR_LANGUAGE, false, true },      // EE_CHAR_LANGUAGE
        { SID_ATTR_CHAR_CJK_LANGUAGE, false, true },  // EE_CHAR_LANGUAGE_CJK
        { SID_ATTR_CHAR_CTL_LANGUAGE, false, true },  // EE_CHAR_LANGUAGE_CTL
        { SID_ATTR_CHAR_CJK_FONT, true, true },      // EE_CHAR_FONTINFO_CJK
        { SID_ATTR_CHAR_CTL_FONT, true, true },      // EE_CHAR_FONTINFO_CTL
        { SID_ATTR_CHAR_CJK_FONTHEIGHT, false, true }, // EE_CHAR_FONTHEIGHT_CJK
        { SID_ATTR_CHAR_CTL_FONTHEIGHT, false, true }, // EE_CHAR_FONTHEIGHT_CTL
        { SID_ATTR_CHAR_CJK_WEIGHT, false, true },    // EE_CHAR_WEIGHT_CJK
        { SID_ATTR_CHAR_CTL_WEIGHT, false, true },    // EE_CHAR_WEIGHT_CTL
        { SID_ATTR_CHAR_CJK_POSTURE, false, true },   // EE_CHAR_ITALIC_CJK
        { SID_ATTR_CHAR_CTL_POSTURE, false, true },   // EE_CHAR_ITALIC_CTL
        { SID_ATTR_CHAR_EMPHASISMARK, false, true },  // EE_CHAR_EMPHASISMARK
        { SID_ATTR_CHAR_RELIEF, false, true },        // EE_CHAR_RELIEF
        { 0, false, true },                           // EE_CHAR_RUBI_DUMMY
        { 0, true, true },                           // EE_CHAR_XMLATTRIBS
        { SID_ATTR_CHAR_OVERLINE, false, true },      // EE_CHAR_OVERLINE
        { SID_ATTR_CHAR_CASEMAP, false, true },       // EE_CHAR_CASEMAP
        { SID_ATTR_CHAR_GRABBAG, false, true },       // EE_CHAR_GRABBAG
        { SID_ATTR_CHAR_BACK_COLOR, false, true },    // EE_CHAR_BKGCOLOR
        { 0, false, true },                           // EE_FEATURE_TAB
        { 0, false, true },                           // EE_FEATURE_LINEBR
        { SID_ATTR_CHAR_CHARSETCOLOR, false, true },  // EE_FEATURE_NOTCONV
        { SID_FIELD, true, true },                    // EE_FEATURE_FIELD
};

EditCharAttrib* MakeCharAttrib( SfxItemPool& rPool, const SfxPoolItem& rAttr, sal_Int32 nS, sal_Int32 nE )
{
    // Create a new attribute in the pool
    const SfxPoolItem& rNew = rPool.Put( rAttr );
    const SfxPoolItem& rNew = rPool.DirectPutItemInPool( rAttr );

    EditCharAttrib* pNew = nullptr;
    switch( rNew.Which() )
@@ -813,7 +815,7 @@ ContentAttribsInfo::ContentAttribsInfo( SfxItemSet aParaAttribs ) :
void ContentAttribsInfo::RemoveAllCharAttribsFromPool(SfxItemPool& rPool) const
{
    for (const std::unique_ptr<EditCharAttrib>& rAttrib : aPrevCharAttribs)
        rPool.Remove(*rAttrib->GetItem());
        rPool.DirectRemoveItemFromPool(*rAttrib->GetItem());
}

void ContentAttribsInfo::AppendCharAttrib(EditCharAttrib* pNew)
@@ -1328,7 +1330,7 @@ void ContentNode::ExpandAttribs( sal_Int32 nIndex, sal_Int32 nNew, SfxItemPool& 
        {
            OSL_FAIL( "Empty Attribute after ExpandAttribs?" );
            bResort = true;
            rItemPool.Remove( *pAttrib->GetItem() );
            rItemPool.DirectRemoveItemFromPool( *pAttrib->GetItem() );
            rAttribs.erase(rAttribs.begin()+nAttr);
        }
        else
@@ -1424,7 +1426,7 @@ void ContentNode::CollapseAttribs( sal_Int32 nIndex, sal_Int32 nDeleted, SfxItem
        if ( bDelAttr )
        {
            bResort = true;
            rItemPool.Remove( *pAttrib->GetItem() );
            rItemPool.DirectRemoveItemFromPool( *pAttrib->GetItem() );
            rAttribs.erase(rAttribs.begin()+nAttr);
        }
        else
@@ -1969,7 +1971,7 @@ void EditDoc::RemoveItemsFromPool(const ContentNode& rNode)
    for (sal_Int32 nAttr = 0; nAttr < rNode.GetCharAttribs().Count(); ++nAttr)
    {
        const EditCharAttrib& rAttr = *rNode.GetCharAttribs().GetAttribs()[nAttr];
        GetItemPool().Remove(*rAttr.GetItem());
        GetItemPool().DirectRemoveItemFromPool(*rAttr.GetItem());
    }
}

@@ -2403,7 +2405,7 @@ void EditDoc::InsertAttribInSelection( ContentNode* pNode, sal_Int32 nStart, sal
    {
        // Will become a large Attribute.
        pEndingAttrib->GetEnd() = pStartingAttrib->GetEnd();
        GetItemPool().Remove( *(pStartingAttrib->GetItem()) );
        GetItemPool().DirectRemoveItemFromPool( *(pStartingAttrib->GetItem()) );
        pNode->GetCharAttribs().Remove(pStartingAttrib);
    }
    else if ( pStartingAttrib && ( *(pStartingAttrib->GetItem()) == rPoolItem ) )
@@ -2525,7 +2527,7 @@ bool EditDoc::RemoveAttribs( ContentNode* pNode, sal_Int32 nStart, sal_Int32 nEn
        {
            DBG_ASSERT( ( pAttr != rpStarting ) && ( pAttr != rpEnding ), "Delete and retain the same attribute?" );
            DBG_ASSERT( !pAttr->IsFeature(), "RemoveAttribs: Remove a feature?!" );
            GetItemPool().Remove( *pAttr->GetItem() );
            GetItemPool().DirectRemoveItemFromPool( *pAttr->GetItem() );
            rAttribs.erase(rAttribs.begin()+nAttr);
        }
        else
@@ -2822,7 +2824,7 @@ void CharAttribList::OptimizeRanges( SfxItemPool& rItemPool )
                if (*rNext.GetItem() == *rAttr.GetItem())
                {
                    rAttr.GetEnd() = rNext.GetEnd();
                    rItemPool.Remove(*rNext.GetItem());
                    rItemPool.DirectRemoveItemFromPool(*rNext.GetItem());
                    aAttribs.erase(aAttribs.begin()+nNext);
                }
                break;  // only 1 attr with same which can start here.
@@ -2998,7 +3000,7 @@ public:
    void operator() (const std::unique_ptr<EditCharAttrib>& r)
    {
        if (r->IsEmpty())
            mrItemPool.Remove(*r->GetItem());
            mrItemPool.DirectRemoveItemFromPool(*r->GetItem());
    }
};

diff --git a/editeng/source/editeng/editobj.cxx b/editeng/source/editeng/editobj.cxx
index d0ec863..ba3aac6 100644
--- a/editeng/source/editeng/editobj.cxx
+++ b/editeng/source/editeng/editobj.cxx
@@ -47,7 +47,7 @@ using namespace com::sun::star;
static XEditAttribute MakeXEditAttribute( SfxItemPool& rPool, const SfxPoolItem& rItem, sal_Int32 nStart, sal_Int32 nEnd )
{
    // Create the new attribute in the pool
    const SfxPoolItem& rNew = rPool.Put( rItem );
    const SfxPoolItem& rNew = rPool.DirectPutItemInPool( rItem );

    return XEditAttribute( rNew, nStart, nEnd );
}
@@ -122,7 +122,7 @@ ContentInfo::ContentInfo( const ContentInfo& rCopyFrom, SfxItemPool& rPoolToUse 
ContentInfo::~ContentInfo()
{
    for (auto const& charAttrib : maCharAttribs)
        aParaAttribs.GetPool()->Remove(*charAttrib.GetItem());
        aParaAttribs.GetPool()->DirectRemoveItemFromPool(*charAttrib.GetItem());
    maCharAttribs.clear();
}

@@ -381,7 +381,7 @@ XEditAttribute EditTextObjectImpl::CreateAttrib( const SfxPoolItem& rItem, sal_I

void EditTextObjectImpl::DestroyAttrib( const XEditAttribute& rAttr )
{
    mpPool->Remove( *rAttr.GetItem() );
    mpPool->DirectRemoveItemFromPool( *rAttr.GetItem() );
}


@@ -540,7 +540,7 @@ bool EditTextObjectImpl::RemoveCharAttribs( sal_uInt16 _nWhich )
            XEditAttribute& rAttr = rC.maCharAttribs[--nAttr];
            if ( !_nWhich || (rAttr.GetItem()->Which() == _nWhich) )
            {
                mpPool->Remove(*rAttr.GetItem());
                mpPool->DirectRemoveItemFromPool(*rAttr.GetItem());
                rC.maCharAttribs.erase(rC.maCharAttribs.begin()+nAttr);
                bChanged = true;
            }
diff --git a/editeng/source/editeng/editobj2.hxx b/editeng/source/editeng/editobj2.hxx
index 86c81e2..8a71474 100644
--- a/editeng/source/editeng/editobj2.hxx
+++ b/editeng/source/editeng/editobj2.hxx
@@ -74,9 +74,7 @@ inline bool XEditAttribute::operator==( const XEditAttribute& rCompare ) const
{
    return  (nStart == rCompare.nStart) &&
            (nEnd == rCompare.nEnd) &&
            ((pItem == rCompare.pItem) ||
             ((pItem->Which() == rCompare.pItem->Which()) &&
              (*pItem == *rCompare.pItem)));
            SfxPoolItem::areSame(pItem, rCompare.pItem);
}

struct XParaPortion
diff --git a/editeng/source/editeng/fieldupdater.cxx b/editeng/source/editeng/fieldupdater.cxx
index 41d9be7..008793a 100644
--- a/editeng/source/editeng/fieldupdater.cxx
+++ b/editeng/source/editeng/fieldupdater.cxx
@@ -47,7 +47,7 @@ public:
                // Create a new table field with the new ID, and set it to the
                // attribute object.
                SvxFieldItem aNewItem(SvxTableField(nTab), EE_FEATURE_FIELD);
                rAttr.SetItem(pPool->Put(aNewItem));
                rAttr.SetItem(pPool->DirectPutItemInPool(aNewItem));
            }
        }
    }
diff --git a/editeng/source/items/textitem.cxx b/editeng/source/items/textitem.cxx
index cac394c1..e242566 100644
--- a/editeng/source/items/textitem.cxx
+++ b/editeng/source/items/textitem.cxx
@@ -159,24 +159,6 @@ bool SvxFontListItem::GetPresentation

// class SvxFontItem -----------------------------------------------------

namespace
{
sal_Int32 CompareTo(sal_Int32 nA, sal_Int32 nB)
{
    if (nA < nB)
    {
        return -1;
    }

    if (nA > nB)
    {
        return 1;
    }

    return 0;
}
}

SvxFontItem::SvxFontItem( const sal_uInt16 nId ) :
    SfxPoolItem( nId )
{
@@ -314,36 +296,6 @@ bool SvxFontItem::operator==( const SfxPoolItem& rAttr ) const
    return bRet;
}

bool SvxFontItem::operator<(const SfxPoolItem& rCmp) const
{
    const auto& rOther = static_cast<const SvxFontItem&>(rCmp);
    sal_Int32 nRet = GetFamilyName().compareTo(rOther.GetFamilyName());
    if (nRet != 0)
    {
        return nRet < 0;
    }

    nRet = GetStyleName().compareTo(rOther.GetStyleName());
    if (nRet != 0)
    {
        return nRet < 0;
    }

    nRet = CompareTo(GetFamily(), rOther.GetFamily());
    if (nRet != 0)
    {
        return nRet < 0;
    }

    nRet = CompareTo(GetPitch(), rOther.GetPitch());
    if (nRet != 0)
    {
        return nRet < 0;
    }

    return GetCharSet() < rOther.GetCharSet();
}

SvxFontItem* SvxFontItem::Clone( SfxItemPool * ) const
{
    return new SvxFontItem( *this );
diff --git a/extensions/source/propctrlr/fontdialog.cxx b/extensions/source/propctrlr/fontdialog.cxx
index 1a10187..5975742 100644
--- a/extensions/source/propctrlr/fontdialog.cxx
+++ b/extensions/source/propctrlr/fontdialog.cxx
@@ -532,26 +532,27 @@ namespace pcr
        // create the pool
        static SfxItemInfo const aItemInfos[FontItemIds::CFID_LAST_ITEM_ID - FontItemIds::CFID_FIRST_ITEM_ID + 1] =
        {
            { SID_ATTR_CHAR_FONT,               false },
            { SID_ATTR_CHAR_FONTHEIGHT,         false },
            { SID_ATTR_CHAR_WEIGHT,             false },
            { SID_ATTR_CHAR_POSTURE,            false },
            { SID_ATTR_CHAR_LANGUAGE,           false },
            { SID_ATTR_CHAR_UNDERLINE,          false },
            { SID_ATTR_CHAR_STRIKEOUT,          false },
            { SID_ATTR_CHAR_WORDLINEMODE,       false },
            { SID_ATTR_CHAR_COLOR,              false },
            { SID_ATTR_CHAR_RELIEF,             false },
            { SID_ATTR_CHAR_EMPHASISMARK,       false },
            { 0,                                false },
            { 0,                                false },
            { 0,                                false },
            { 0,                                false },
            { 0,                                false },
            { 0,                                false },
            { 0,                                false },
            { 0,                                false },
            { SID_ATTR_CHAR_FONTLIST,           false }
            // _nSID, _bNeedsPoolRegistration, _bShareable
            { SID_ATTR_CHAR_FONT,               false, false },
            { SID_ATTR_CHAR_FONTHEIGHT,         false, false },
            { SID_ATTR_CHAR_WEIGHT,             false, false },
            { SID_ATTR_CHAR_POSTURE,            false, false },
            { SID_ATTR_CHAR_LANGUAGE,           false, false },
            { SID_ATTR_CHAR_UNDERLINE,          false, false },
            { SID_ATTR_CHAR_STRIKEOUT,          false, false },
            { SID_ATTR_CHAR_WORDLINEMODE,       false, false },
            { SID_ATTR_CHAR_COLOR,              false, false },
            { SID_ATTR_CHAR_RELIEF,             false, false },
            { SID_ATTR_CHAR_EMPHASISMARK,       false, false },
            { 0,                                false, false },
            { 0,                                false, false },
            { 0,                                false, false },
            { 0,                                false, false },
            { 0,                                false, false },
            { 0,                                false, false },
            { 0,                                false, false },
            { 0,                                false, false },
            { SID_ATTR_CHAR_FONTLIST,           false, false }
        };

        _rpPool = new SfxItemPool("PCRControlFontItemPool", FontItemIds::CFID_FIRST_ITEM_ID, FontItemIds::CFID_LAST_ITEM_ID,
diff --git a/include/editeng/fontitem.hxx b/include/editeng/fontitem.hxx
index deabf31..7cab5f4 100644
--- a/include/editeng/fontitem.hxx
+++ b/include/editeng/fontitem.hxx
@@ -46,7 +46,6 @@ public:

    // "pure virtual Methods" from SfxPoolItem
    virtual bool operator==(const SfxPoolItem& rItem) const override;
    bool operator<(const SfxPoolItem& rCmp) const override;
    virtual SvxFontItem* 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;
diff --git a/include/editeng/wghtitem.hxx b/include/editeng/wghtitem.hxx
index 6f5f4b3..121cfcf 100644
--- a/include/editeng/wghtitem.hxx
+++ b/include/editeng/wghtitem.hxx
@@ -59,14 +59,6 @@ public:
    FontWeight              GetWeight() const { return GetValue(); }

    void dumpAsXml(xmlTextWriterPtr pWriter) const override;

    virtual bool IsSortable() const override { return true; }

    virtual bool operator<(const SfxPoolItem& rCmp) const override
    {
        auto const & other = static_cast<const SvxWeightItem&>(rCmp);
        return GetValue() < other.GetValue();
    }
};

#endif // INCLUDED_EDITENG_WGHTITEM_HXX
diff --git a/include/sal/log-areas.dox b/include/sal/log-areas.dox
index 8e6d5d8..0b3907e 100644
--- a/include/sal/log-areas.dox
+++ b/include/sal/log-areas.dox
@@ -499,6 +499,7 @@ certain functionality.
@li @c vcl.helper
@li @c vcl.icontest
@li @c vcl.ios.clipboard
@li @c vcl.items
@li @c vcl.kf5 - KF5
@li @c vcl.layout - Widget layout
@li @c vcl.lazydelete
diff --git a/include/svl/custritm.hxx b/include/svl/custritm.hxx
index 90215af..3159c41 100644
--- a/include/svl/custritm.hxx
+++ b/include/svl/custritm.hxx
@@ -39,8 +39,6 @@ public:
    {}

    virtual bool operator ==(const SfxPoolItem & rItem) const override;
    virtual bool operator <(const SfxPoolItem & rItem) const override;
    virtual bool IsSortable() const override { return true; }

    virtual bool GetPresentation(SfxItemPresentation,
                                 MapUnit, MapUnit,
diff --git a/include/svl/itempool.hxx b/include/svl/itempool.hxx
index e85451e..8dfac47 100644
--- a/include/svl/itempool.hxx
+++ b/include/svl/itempool.hxx
@@ -26,6 +26,7 @@
#include <svl/whichranges.hxx>
#include <memory>
#include <vector>
#include <unordered_set>
#include <o3tl/sorted_vector.hxx>
#include <salhelper/simplereferenceobject.hxx>

@@ -34,11 +35,30 @@ struct SfxItemPool_Impl;

struct SfxItemInfo
{
    // Defines a mapping between WhichID <-> SlotID
    sal_uInt16       _nSID;
    bool            _bPoolable;

    // Defines if this Item needs to be registered at the pool
    // to make it accessible for the GetItemSurrogates call. It
    // will not be included when this flag is not set, but also
    // needs no registration. There are SAL_INFO calls in the
    // GetItemSurrogates impl that will mention that
    bool             _bNeedsPoolRegistration : 1;

    // Defines if the Item can be shared/RefCounted else it will be cloned.
    // Default is true - as it should be for all Items. It is needed by some
    // SW items, so protected to let them set it in constructor. If this could
    // be fixed at that Items we may remove this again.
    bool             _bShareable : 1;
};

class SfxItemPool;
typedef std::unordered_set<const SfxPoolItem*> registeredSfxPoolItems;

#ifdef DBG_UTIL
SVL_DLLPUBLIC size_t getAllDirectlyPooledSfxPoolItemCount();
SVL_DLLPUBLIC size_t getRemainingDirectlyPooledSfxPoolItemCount();
#endif

/** Base class for providers of defaults of SfxPoolItems.
 *
@@ -53,14 +73,26 @@ class SVL_DLLPUBLIC SfxItemPool : public salhelper::SimpleReferenceObject
    friend class SfxItemSet;
    friend class SfxAllItemSet;

    // allow ItemSetTooling to access
    friend SfxPoolItem const* implCreateItemEntry(SfxItemPool&, SfxPoolItem const*, sal_uInt16, bool, bool);
    friend void implCleanupItemEntry(SfxItemPool&, SfxPoolItem const*);

    // unit testing
    friend class PoolItemTest;

    const SfxItemInfo*              pItemInfos;
    std::unique_ptr<SfxItemPool_Impl>               pImpl;

    registeredSfxPoolItems** ppRegisteredSfxPoolItems;

private:
    sal_uInt16                      GetIndex_Impl(sal_uInt16 nWhich) const;
    sal_uInt16                      GetSize_Impl() const;

    SVL_DLLPRIVATE bool             IsItemPoolable_Impl( sal_uInt16 nWhich ) const;
    SVL_DLLPRIVATE bool             NeedsPoolRegistration_Impl(sal_uInt16 nPos) const
    { return pItemInfos[nPos]._bNeedsPoolRegistration; }
    SVL_DLLPRIVATE bool             Shareable_Impl(sal_uInt16 nPos) const
    { return pItemInfos[nPos]._bShareable; }

public:
    // for default SfxItemSet::CTOR, set default WhichRanges
@@ -135,18 +167,16 @@ public:
    virtual rtl::Reference<SfxItemPool> Clone() const;
    const OUString&                 GetName() const;

    template<class T> const T&      Put( std::unique_ptr<T> xItem, sal_uInt16 nWhich = 0 )
    { return static_cast<const T&>(PutImpl( *xItem.release(), nWhich, /*bPassingOwnership*/true)); }
    template<class T> const T&      Put( const T& rItem, sal_uInt16 nWhich = 0 )
    { return static_cast<const T&>(PutImpl( rItem, nWhich, /*bPassingOwnership*/false)); }
    void                            Remove( const SfxPoolItem& );
    template<class T> const T&      DirectPutItemInPool( std::unique_ptr<T> xItem, sal_uInt16 nWhich = 0 )
    { return static_cast<const T&>(DirectPutItemInPoolImpl( *xItem.release(), nWhich, /*bPassingOwnership*/true)); }
    template<class T> const T&      DirectPutItemInPool( const T& rItem, sal_uInt16 nWhich = 0 )
    { return static_cast<const T&>(DirectPutItemInPoolImpl( rItem, nWhich, /*bPassingOwnership*/false)); }
    void                            DirectRemoveItemFromPool( const SfxPoolItem& );

    const SfxPoolItem&              GetDefaultItem( sal_uInt16 nWhich ) const;
    template<class T> const T&      GetDefaultItem( TypedWhichId<T> nWhich ) const
    { return static_cast<const T&>(GetDefaultItem(sal_uInt16(nWhich))); }

    bool                            CheckItemInPool(const SfxPoolItem *) const;

    struct Item2Range
    {
        o3tl::sorted_vector<SfxPoolItem*>::const_iterator m_begin;
@@ -158,8 +188,7 @@ public:
    template<class T> const T*      GetItem2Default( TypedWhichId<T> nWhich ) const
    { return static_cast<const T*>(GetItem2Default(sal_uInt16(nWhich))); }

    sal_uInt32                      GetItemCount2(sal_uInt16 nWhich) const;
    Item2Range                      GetItemSurrogates(sal_uInt16 nWhich) const;
    const registeredSfxPoolItems&   GetItemSurrogates(sal_uInt16 nWhich) const;
    /*
        This is only valid for SfxPoolItem that override IsSortable and operator<.
        Returns a range of items defined by using operator<.
@@ -179,9 +208,14 @@ public:

    void                            Delete();

    bool                            IsItemPoolable( sal_uInt16 nWhich ) const;
    bool                            IsItemPoolable( const SfxPoolItem &rItem ) const
                                    { return IsItemPoolable( rItem.Which() ); }
    bool                            NeedsPoolRegistration(sal_uInt16 nWhich) const;
    bool                            NeedsPoolRegistration(const SfxPoolItem &rItem) const
                                    { return NeedsPoolRegistration(rItem.Which()); }

    bool                            Shareable(sal_uInt16 nWhich) const;
    bool                            Shareable(const SfxPoolItem &rItem) const
                                    { return Shareable(rItem.Which()); }

    void                            SetItemInfos( const SfxItemInfo *pInfos );
    sal_uInt16                      GetWhich( sal_uInt16 nSlot, bool bDeep = true ) const;
    template<class T>
@@ -196,10 +230,34 @@ public:
    static bool                     IsSlot(sal_uInt16 nId) {
                                        return nId && nId > SFX_WHICH_MAX; }

    // this method tries to register an Item at this Pool. If this
    // is done depends on the SfxItemInfo-flag _bNeedsPoolRegistration
    // which needs to be set for Items that are acessed using
    // GetItemSurrogates, else the Item will not be returned/accessed
    void tryRegisterSfxPoolItem(const SfxPoolItem& rItem, bool bPoolDirect);

    // this method will register the Item at this Pool, no matter what.
    // It is needed for all calls that directly register Items at the
    // Pool, so the DirectPutItemInPool-methods
    void doRegisterSfxPoolItem(const SfxPoolItem& rItem);

    // this method will unregister an Item from this Pool
    void unregisterSfxPoolItem(const SfxPoolItem& rItem);

    // check if this Item is registered at this Pool, needed to detect
    // if an Item is to be set at another Pool and needs to be cloned
    bool isSfxPoolItemRegisteredAtThisPool(const SfxPoolItem& rItem) const;

    // try to find an equal existing Item to given one in pool
    const SfxPoolItem* tryToGetEqualItem(const SfxPoolItem& rItem, sal_uInt16 nWhich) const;

    void                            dumpAsXml(xmlTextWriterPtr pWriter) const;

protected:
    virtual const SfxPoolItem&      PutImpl( const SfxPoolItem&, sal_uInt16 nWhich = 0, bool bPassingOwnership = false );
    const SfxPoolItem&      DirectPutItemInPoolImpl( const SfxPoolItem&, sal_uInt16 nWhich = 0, bool bPassingOwnership = false );
    virtual void newItem_Callback(const SfxPoolItem& rItem) const;
    virtual bool newItem_UseDirect(const SfxPoolItem& rItem) const;

private:
    const SfxItemPool&              operator=(const SfxItemPool &) = delete;

diff --git a/include/svl/itemset.hxx b/include/svl/itemset.hxx
index 01d9d50..06e82b8 100644
--- a/include/svl/itemset.hxx
+++ b/include/svl/itemset.hxx
@@ -36,11 +36,19 @@ SVL_DLLPUBLIC size_t getAllocatedSfxItemSetCount();
SVL_DLLPUBLIC size_t getUsedSfxItemSetCount();
#endif

// ItemSet/ItemPool helpers
SfxPoolItem const* implCreateItemEntry(SfxItemPool& rPool, SfxPoolItem const* pSource, sal_uInt16 nWhich, bool bPassingOwnership, bool bPoolDirect);
void implCleanupItemEntry(SfxItemPool& rPool, SfxPoolItem const* pSource);

class SAL_WARN_UNUSED SVL_DLLPUBLIC SfxItemSet
{
    friend class SfxItemIter;
    friend class SfxWhichIter;

    // allow ItemSetTooling to access
    friend SfxPoolItem const* implCreateItemEntry(SfxItemPool&, SfxPoolItem const*, sal_uInt16, bool, bool);
    friend void implCleanupItemEntry(SfxItemPool&, SfxPoolItem const*);

    SfxItemPool*      m_pPool;         ///< pool that stores the items
    const SfxItemSet* m_pParent;       ///< derivation
    sal_uInt16        m_nCount;        ///< number of items
@@ -88,7 +96,7 @@ private:
    const SfxItemSet&           operator=(const SfxItemSet &) = delete;

protected:
    virtual const SfxPoolItem*  PutImpl( const SfxPoolItem&, sal_uInt16 nWhich, bool bItemIsSetMember, bool bPassingOwnership );
    virtual const SfxPoolItem*  PutImpl( const SfxPoolItem&, sal_uInt16 nWhich, bool bPassingOwnership );

    /** special constructor for SfxAllItemSet */
    enum class SfxAllItemSetFlag { Flag };
@@ -207,9 +215,9 @@ public:
    // add, delete items, work on items
public:
    const SfxPoolItem*          Put( const SfxPoolItem& rItem, sal_uInt16 nWhich )
    { return PutImpl(rItem, nWhich, /*bItemIsSetMember*/false, /*bPassingOwnership*/false); }
    { return PutImpl(rItem, nWhich, /*bPassingOwnership*/false); }
    const SfxPoolItem*          Put( std::unique_ptr<SfxPoolItem> xItem, sal_uInt16 nWhich )
    { return PutImpl(*xItem.release(), nWhich, /*bItemIsSetMember*/false, /*bPassingOwnership*/true); }
    { return PutImpl(*xItem.release(), nWhich, /*bPassingOwnership*/true); }
    const SfxPoolItem*          Put( const SfxPoolItem& rItem )
                                { return Put(rItem, rItem.Which()); }
    const SfxPoolItem*          Put( std::unique_ptr<SfxPoolItem> xItem )
@@ -261,7 +269,7 @@ private:
    sal_uInt16 ClearAllItemsImpl();

    // Merge two given Item(entries)
    void MergeItem_Impl(const SfxPoolItem **ppFnd1, const SfxPoolItem *pFnd2, bool bItemIsSetMember, bool bIgnoreDefaults);
    void MergeItem_Impl(const SfxPoolItem **ppFnd1, const SfxPoolItem *pFnd2, bool bIgnoreDefaults);

    // split version(s) of InvalidateItem for input types WhichID and Offset
    void InvalidateItem_ForWhichID(sal_uInt16 nWhich);
@@ -270,9 +278,6 @@ private:
    // split version(s) of GetItemStateImpl for input types WhichID and Offset
    SfxItemState GetItemState_ForWhichID( SfxItemState eState, sal_uInt16 nWhich, bool bSrchInParent, const SfxPoolItem **ppItem) const;
    SfxItemState GetItemState_ForOffset( sal_uInt16 nOffset, const SfxPoolItem **ppItem) const;

    SfxPoolItem const* implCreateItemEntry(SfxPoolItem const* pSource, sal_uInt16 nWhich, bool bItemIsSetMember, bool bPassingOwnership);
    void implCleanupItemEntry(SfxPoolItem const* pSource);
};

inline void SfxItemSet::SetParent( const SfxItemSet* pNew )
@@ -292,7 +297,7 @@ public:

    virtual std::unique_ptr<SfxItemSet> Clone( bool bItems = true, SfxItemPool *pToPool = nullptr ) const override;
private:
    virtual const SfxPoolItem*  PutImpl( const SfxPoolItem&, sal_uInt16 nWhich, bool bItemIsSetMember,bool bPassingOwnership ) override;
    virtual const SfxPoolItem*  PutImpl( const SfxPoolItem&, sal_uInt16 nWhich, bool bPassingOwnership ) override;
};


diff --git a/include/svl/poolitem.hxx b/include/svl/poolitem.hxx
index 4714e2f..b434302 100644
--- a/include/svl/poolitem.hxx
+++ b/include/svl/poolitem.hxx
@@ -100,6 +100,7 @@ enum class SfxItemState {
#ifdef DBG_UTIL
SVL_DLLPUBLIC size_t getAllocatedSfxPoolItemCount();
SVL_DLLPUBLIC size_t getUsedSfxPoolItemCount();
SVL_DLLPUBLIC void listAllocatedSfxPoolItems();
#endif

class SfxItemPool;
@@ -108,31 +109,40 @@ typedef struct _xmlTextWriter* xmlTextWriterPtr;

class SVL_DLLPUBLIC SfxPoolItem
{
friend class SfxItemPool;
friend class SfxItemDisruptor_Impl;
friend class SfxItemPoolCache;
friend class SfxItemSet;
    friend class SfxItemPool;
    friend class SfxItemDisruptor_Impl;
    friend class SfxItemPoolCache;
    friend class SfxItemSet;

    // allow ItemSetTooling to access
    friend SfxPoolItem const* implCreateItemEntry(SfxItemPool&, SfxPoolItem const*, sal_uInt16, bool, bool);
    friend void implCleanupItemEntry(SfxItemPool&, SfxPoolItem const*);

    mutable sal_uInt32 m_nRefCount;
    sal_uInt16  m_nWhich;

#ifdef DBG_UTIL
    // for debugging add a serial number, will be set in the constructor
    // and count up from zero. If you have a deterministic error case and
    // see the Item involved in the debugger you can  use that number in
    // the next run to see where that Item gets constructed and how it is
    // involved/ processed
    sal_uInt32  m_nSerialNumber;
#endif

    // bitfield for flags (instead of SfxItemKind)
    bool        m_bIsVoidItem : 1;
    bool        m_bDeleteOnIdle : 1;
    bool        m_bStaticDefault : 1;
    bool        m_bPoolDefault : 1;
    bool        m_bIsVoidItem : 1;          // bit 0
    bool        m_bDeleteOnIdle : 1;        // bit 1
    bool        m_bStaticDefault : 1;       // bit 2
    bool        m_bPoolDefault : 1;         // bit 3
    bool        m_bRegisteredAtPool : 1;    // bit 4
    bool        m_bNewItemCallback : 1;     // bit 5
    bool        m_bIsSetItem : 1;           // bit 6

protected:
    // Defines if the Item can be shared/RefCounted else it will be cloned.
    // Default is true - as it should be for all Items. It is needed by some
    // SW items, so protected to let them set it in constructor. If this could
    // be fixed at that Items we may remove this again.
    bool        m_bShareable : 1;

private:
#ifdef DBG_UTIL
    // this flag will make debugging item stuff much simpler
    bool        m_bDeleted : 1;
    bool        m_bDeleted : 1;             // bit 7
#endif

private:
@@ -143,10 +153,13 @@ private:
    }

protected:
    void setVoidItem() { m_bIsVoidItem = true; }
    void setIsVoidItem() { m_bIsVoidItem = true; }
    void setDeleteOnIdle() { m_bDeleteOnIdle = true; }
    void setStaticDefault() { m_bStaticDefault = true; }
    void setPoolDefault() { m_bPoolDefault = true; }
    void setRegisteredAtPool(bool bNew) { m_bRegisteredAtPool = bNew; }
    void setNewItemCallback() { m_bNewItemCallback = true; }
    void setIsSetItem() { m_bIsSetItem = true; }

public:
    inline void AddRef(sal_uInt32 n = 1) const
@@ -156,11 +169,23 @@ public:
        m_nRefCount += n;
    }

#ifdef DBG_UTIL
    sal_uInt32 getSerialNumber() const { return m_nSerialNumber; }
#endif

    bool isVoidItem() const { return m_bIsVoidItem; }
    bool isDeleteOnIdle() const { return m_bDeleteOnIdle; }
    bool isStaticDefault() const { return m_bStaticDefault; }
    bool isPoolDefault() const { return m_bPoolDefault; }
    bool isShareable() const { return m_bShareable; }
    bool isRegisteredAtPool() const { return m_bRegisteredAtPool; }
    bool isNewItemCallback() const { return m_bNewItemCallback; }
    bool isSetItem() const { return m_bIsSetItem; }

    // version that allows nullptrs
    static bool areSame(const SfxPoolItem* pItem1, const SfxPoolItem* pItem2);

    // if you have the items (not nullptrs) use this version
    static bool areSame(const SfxPoolItem& rItem1, const SfxPoolItem& rItem2);

private:
    inline sal_uInt32 ReleaseRef(sal_uInt32 n = 1) const
@@ -223,24 +248,6 @@ public:
    bool                     operator!=( const SfxPoolItem& rItem ) const
                             { return !(*this == rItem); }

    // Sorting is only used for faster searching in a pool which contains large quantities
    // of a single kind of pool item.
    virtual bool             operator<( const SfxPoolItem& ) const { assert(false); return false; }
    virtual bool             IsSortable() const { return false; }

    // Some item types cannot be IsSortable() (such as because they are modified while stored
    // in a pool, which would change the ordering position, see e.g. 585e0ac43b9bd8a2f714903034).
    // To improve performance in such cases it is possible to reimplement Lookup() to do a linear
    // lookup optimized for the specific class (avoiding virtual functions may allow the compiler
    // to generate better code and class-specific optimizations such as hashing or caching may
    // be used.)
    // If reimplemented, the Lookup() function should search [begin,end) for an item matching
    // this object and return an iterator pointing to the item or the end iterator.
    virtual bool             HasLookup() const { return false; }
    typedef std::vector<SfxPoolItem*>::const_iterator lookup_iterator;
    virtual lookup_iterator  Lookup(lookup_iterator /*begin*/, lookup_iterator end ) const
                             { assert( false ); return end; }

    /**  @return true if it has a valid string representation */
    virtual bool             GetPresentation( SfxItemPresentation ePresentation,
                                    MapUnit eCoreMetric,
@@ -299,6 +306,8 @@ inline bool IsInvalidItem(const SfxPoolItem *pItem)
    return pItem == INVALID_POOL_ITEM;
}

SVL_DLLPUBLIC bool areSfxPoolItemPtrsEqual(const SfxPoolItem* pItem1, const SfxPoolItem* pItem2);

class SVL_DLLPUBLIC SfxPoolItemHint final : public SfxHint
{
    SfxPoolItem* pObj;
diff --git a/include/svx/pageitem.hxx b/include/svx/pageitem.hxx
index 32702fe..de93730 100644
--- a/include/svx/pageitem.hxx
+++ b/include/svx/pageitem.hxx
@@ -98,7 +98,7 @@ class SVX_DLLPUBLIC SvxSetItem final : public SfxSetItem
{
public:
    SvxSetItem( const TypedWhichId<SvxSetItem> nId, const SfxItemSet& rSet );
    SvxSetItem( const SvxSetItem& rItem );
    SvxSetItem( const SvxSetItem& rItem, SfxItemPool* pPool = nullptr );
    SvxSetItem( const TypedWhichId<SvxSetItem> nId, SfxItemSet&& pSet );

    virtual SvxSetItem* Clone( SfxItemPool *pPool = nullptr ) const override;
diff --git a/include/svx/sdasitm.hxx b/include/svx/sdasitm.hxx
index e53e9c3..cb7230a 100644
--- a/include/svx/sdasitm.hxx
+++ b/include/svx/sdasitm.hxx
@@ -70,8 +70,6 @@ private:
            SdrCustomShapeGeometryItem & operator =(SdrCustomShapeGeometryItem &&) = delete; // due to SfxPoolItem

            virtual bool                operator==( const SfxPoolItem& ) const override;
            virtual bool                operator<( const SfxPoolItem& ) const override;
            virtual bool                IsSortable() const override { return true; }

            virtual bool GetPresentation(SfxItemPresentation ePresentation,
                                         MapUnit eCoreMetric, MapUnit ePresentationMetric,
diff --git a/include/svx/xbtmpit.hxx b/include/svx/xbtmpit.hxx
index 0882081..6d7d75f 100644
--- a/include/svx/xbtmpit.hxx
+++ b/include/svx/xbtmpit.hxx
@@ -41,8 +41,6 @@ public:
            XFillBitmapItem( const XFillBitmapItem& rItem );

    virtual bool            operator==( const SfxPoolItem& rItem ) const override;
    // no idea why, but this item does not play nice with the sorting optimisation, get failures in sd_import_tests
    virtual bool            IsSortable() const override { return false; }
    virtual XFillBitmapItem* Clone( SfxItemPool* pPool = nullptr ) const override;

    virtual bool            QueryValue( css::uno::Any& rVal, sal_uInt8 nMemberId = 0 ) const override;
diff --git a/reportdesign/source/ui/misc/UITools.cxx b/reportdesign/source/ui/misc/UITools.cxx
index 8d32c4e..9ac14c4 100644
--- a/reportdesign/source/ui/misc/UITools.cxx
+++ b/reportdesign/source/ui/misc/UITools.cxx
@@ -559,67 +559,68 @@ bool openCharDialog( const uno::Reference<report::XReportControlFormat >& _rxRep
    // UNO->ItemSet
    static SfxItemInfo aItemInfos[] =
    {
        { 0,      true }, // XATTR_FILLSTYLE
        { 0,      true }, // XATTR_FILLCOLOR
        { 0,       true }, // XATTR_FILLGRADIENT
        { 0,      true }, // XATTR_FILLHATCH
        { 0,     true }, // XATTR_FILLBITMAP
        { 0,       true }, // XATTR_FILLTRANSPARENCE
        { 0,      true }, // XATTR_GRADIENTSTEPCOUNT
        { 0,       true }, // XATTR_FILLBMP_TILE
        { 0,        true }, // XATTR_FILLBMP_POS
        { 0,      true }, // XATTR_FILLBMP_SIZEX
        { 0,      true }, // XATTR_FILLBMP_SIZEY
        { 0,  true }, // XATTR_FILLFLOATTRANSPARENCE
        { 0,     true }, // XATTR_SECONDARYFILLCOLOR
        { 0,        true }, // XATTR_FILLBMP_SIZELOG
        { 0,    true }, // XATTR_FILLBMP_TILEOFFSETX
        { 0,    true }, // XATTR_FILLBMP_TILEOFFSETY
        { 0,        true }, // XATTR_FILLBMP_STRETCH
        { 0,     true }, // XATTR_FILLBMP_POSOFFSETX
        { 0,     true }, // XATTR_FILLBMP_POSOFFSETY
        { 0,     true }, // XATTR_FILLBACKGROUND
        // _nSID, _bNeedsPoolRegistration, _bShareable
        { 0, false, true }, // XATTR_FILLSTYLE
        { 0, true,  true }, // XATTR_FILLCOLOR
        { 0, false, true }, // XATTR_FILLGRADIENT
        { 0, false, true }, // XATTR_FILLHATCH
        { 0, false, true }, // XATTR_FILLBITMAP
        { 0, false, true }, // XATTR_FILLTRANSPARENCE
        { 0, false, true }, // XATTR_GRADIENTSTEPCOUNT
        { 0, false, true }, // XATTR_FILLBMP_TILE
        { 0, false, true }, // XATTR_FILLBMP_POS
        { 0, false, true }, // XATTR_FILLBMP_SIZEX
        { 0, false, true }, // XATTR_FILLBMP_SIZEY
        { 0, false, true }, // XATTR_FILLFLOATTRANSPARENCE
        { 0, false, true }, // XATTR_SECONDARYFILLCOLOR
        { 0, false, true }, // XATTR_FILLBMP_SIZELOG
        { 0, false, true }, // XATTR_FILLBMP_TILEOFFSETX
        { 0, false, true }, // XATTR_FILLBMP_TILEOFFSETY
        { 0, false, true }, // XATTR_FILLBMP_STRETCH
        { 0, false, true }, // XATTR_FILLBMP_POSOFFSETX
        { 0, false, true }, // XATTR_FILLBMP_POSOFFSETY
        { 0, false, true }, // XATTR_FILLBACKGROUND

        { SID_ATTR_CHAR_FONT, true },
        { SID_ATTR_CHAR_FONTHEIGHT, true },
        { SID_ATTR_CHAR_LANGUAGE, true },
        { SID_ATTR_CHAR_POSTURE, true },
        { SID_ATTR_CHAR_WEIGHT, true },
        { SID_ATTR_CHAR_SHADOWED, true },
        { SID_ATTR_CHAR_WORDLINEMODE, true },
        { SID_ATTR_CHAR_CONTOUR, true },
        { SID_ATTR_CHAR_STRIKEOUT, true },
        { SID_ATTR_CHAR_UNDERLINE, true },
        { SID_ATTR_CHAR_COLOR, true },
        { SID_ATTR_CHAR_KERNING, true },
        { SID_ATTR_CHAR_CASEMAP, true },
        { SID_ATTR_CHAR_ESCAPEMENT, true },
        { SID_ATTR_CHAR_FONTLIST, true },
        { SID_ATTR_CHAR_AUTOKERN, true },
        { SID_COLOR_TABLE, true },
        { SID_ATTR_FLASH, true },
        { SID_ATTR_CHAR_EMPHASISMARK, true },
        { SID_ATTR_CHAR_TWO_LINES, true },
        { SID_ATTR_CHAR_ROTATED, true },
        { SID_ATTR_CHAR_SCALEWIDTH, true },
        { SID_ATTR_CHAR_RELIEF, true },
        { SID_ATTR_CHAR_HIDDEN, true },
        { SID_ATTR_BRUSH, true },
        { SID_ATTR_ALIGN_HOR_JUSTIFY, true },
        { SID_ATTR_ALIGN_VER_JUSTIFY, true },
        { SID_ATTR_CHAR_FONT,           false, true },
        { SID_ATTR_CHAR_FONTHEIGHT,     false, true },
        { SID_ATTR_CHAR_LANGUAGE,       false, true },
        { SID_ATTR_CHAR_POSTURE,        false, true },
        { SID_ATTR_CHAR_WEIGHT,         false, true },
        { SID_ATTR_CHAR_SHADOWED,       false, true },
        { SID_ATTR_CHAR_WORDLINEMODE,   false, true },
        { SID_ATTR_CHAR_CONTOUR,        false, true },
        { SID_ATTR_CHAR_STRIKEOUT,      false, true },
        { SID_ATTR_CHAR_UNDERLINE,      false, true },
        { SID_ATTR_CHAR_COLOR,          false, true },
        { SID_ATTR_CHAR_KERNING,        false, true },
        { SID_ATTR_CHAR_CASEMAP,        false, true },
        { SID_ATTR_CHAR_ESCAPEMENT,     false, true },
        { SID_ATTR_CHAR_FONTLIST,       false, true },
        { SID_ATTR_CHAR_AUTOKERN,       false, true },
        { SID_COLOR_TABLE,              false, true },
        { SID_ATTR_FLASH,               false, true },
        { SID_ATTR_CHAR_EMPHASISMARK,   false, true },
        { SID_ATTR_CHAR_TWO_LINES,      false, true },
        { SID_ATTR_CHAR_ROTATED,        false, true },
        { SID_ATTR_CHAR_SCALEWIDTH,     false, true },
        { SID_ATTR_CHAR_RELIEF,         false, true },
        { SID_ATTR_CHAR_HIDDEN,         false, true },
        { SID_ATTR_BRUSH,               false, true },
        { SID_ATTR_ALIGN_HOR_JUSTIFY,   false, true },
        { SID_ATTR_ALIGN_VER_JUSTIFY,   false, true },

        // Asian
        { SID_ATTR_CHAR_CJK_FONT, true },
        { SID_ATTR_CHAR_CJK_FONTHEIGHT, true },
        { SID_ATTR_CHAR_CJK_LANGUAGE, true },
        { SID_ATTR_CHAR_CJK_POSTURE, true },
        { SID_ATTR_CHAR_CJK_WEIGHT, true },
        { SID_ATTR_CHAR_CJK_FONT,       false, true },
        { SID_ATTR_CHAR_CJK_FONTHEIGHT, false, true },
        { SID_ATTR_CHAR_CJK_LANGUAGE,   false, true },
        { SID_ATTR_CHAR_CJK_POSTURE,    false, true },
        { SID_ATTR_CHAR_CJK_WEIGHT,     false, true },
        // Complex
        { SID_ATTR_CHAR_CTL_FONT, true },
        { SID_ATTR_CHAR_CTL_FONTHEIGHT, true },
        { SID_ATTR_CHAR_CTL_LANGUAGE, true },
        { SID_ATTR_CHAR_CTL_POSTURE, true },
        { SID_ATTR_CHAR_CTL_WEIGHT, true }
        { SID_ATTR_CHAR_CTL_FONT,       false, true },
        { SID_ATTR_CHAR_CTL_FONTHEIGHT, false, true },
        { SID_ATTR_CHAR_CTL_LANGUAGE,   false, true },
        { SID_ATTR_CHAR_CTL_POSTURE,    false, true },
        { SID_ATTR_CHAR_CTL_WEIGHT,     false, true }
    };
    FontList aFontList(Application::GetDefaultDevice());
    XColorListRef pColorList( XColorList::CreateStdColorList() );
diff --git a/reportdesign/source/ui/report/ReportController.cxx b/reportdesign/source/ui/report/ReportController.cxx
index 69929a2..351d28f 100644
--- a/reportdesign/source/ui/report/ReportController.cxx
+++ b/reportdesign/source/ui/report/ReportController.cxx
@@ -2331,35 +2331,36 @@ void OReportController::openPageDialog(const uno::Reference<report::XSection>& _
    // UNO->ItemSet
    static SfxItemInfo aItemInfos[] =
    {
        { SID_ATTR_LRSPACE,     true },
        { SID_ATTR_ULSPACE,     true },
        { SID_ATTR_PAGE,        true },
        { SID_ATTR_PAGE_SIZE,   true },
        { SID_ENUM_PAGE_MODE,   true },
        { SID_PAPER_START,      true },
        { SID_PAPER_END,        true },
        { SID_ATTR_BRUSH,       true },
        { 0,      true }, // XATTR_FILLSTYLE
        { 0,      true }, // XATTR_FILLCOLOR
        { 0,       true }, // XATTR_FILLGRADIENT
        { 0,      true }, // XATTR_FILLHATCH
        { 0,     true }, // XATTR_FILLBITMAP
        { 0,       true }, // XATTR_FILLTRANSPARENCE
        { 0,      true }, // XATTR_GRADIENTSTEPCOUNT
        { 0,       true }, // XATTR_FILLBMP_TILE
        { 0,        true }, // XATTR_FILLBMP_POS
        { 0,      true }, // XATTR_FILLBMP_SIZEX
        { 0,      true }, // XATTR_FILLBMP_SIZEY
        { 0,  true }, // XATTR_FILLFLOATTRANSPARENCE
        { 0,     true }, // XATTR_SECONDARYFILLCOLOR
        { 0,        true }, // XATTR_FILLBMP_SIZELOG
        { 0,    true }, // XATTR_FILLBMP_TILEOFFSETX
        { 0,    true }, // XATTR_FILLBMP_TILEOFFSETY
        { 0,        true }, // XATTR_FILLBMP_STRETCH
        { 0,     true }, // XATTR_FILLBMP_POSOFFSETX
        { 0,     true }, // XATTR_FILLBMP_POSOFFSETY
        { 0,     true }, // XATTR_FILLBACKGROUND
        { SID_ATTR_METRIC,      true }
        // _nSID, _bNeedsPoolRegistration, _bShareable
        { SID_ATTR_LRSPACE,     false, true },
        { SID_ATTR_ULSPACE,     false, true },
        { SID_ATTR_PAGE,        false, true },
        { SID_ATTR_PAGE_SIZE,   false, true },
        { SID_ENUM_PAGE_MODE,   false, true },
        { SID_PAPER_START,      false, true },
        { SID_PAPER_END,        false, true },
        { SID_ATTR_BRUSH,       false, true },
        { 0,                    false, true }, // XATTR_FILLSTYLE
        { 0,                    true,  true }, // XATTR_FILLCOLOR
        { 0,                    false, true }, // XATTR_FILLGRADIENT
        { 0,                    false, true }, // XATTR_FILLHATCH
        { 0,                    false, true }, // XATTR_FILLBITMAP
        { 0,                    false, true }, // XATTR_FILLTRANSPARENCE
        { 0,                    false, true }, // XATTR_GRADIENTSTEPCOUNT
        { 0,                    false, true }, // XATTR_FILLBMP_TILE
        { 0,                    false, true }, // XATTR_FILLBMP_POS
        { 0,                    false, true }, // XATTR_FILLBMP_SIZEX
        { 0,                    false, true }, // XATTR_FILLBMP_SIZEY
        { 0,                    false, true }, // XATTR_FILLFLOATTRANSPARENCE
        { 0,                    false, true }, // XATTR_SECONDARYFILLCOLOR
        { 0,                    false, true }, // XATTR_FILLBMP_SIZELOG
        { 0,                    false, true }, // XATTR_FILLBMP_TILEOFFSETX
        { 0,                    false, true }, // XATTR_FILLBMP_TILEOFFSETY
        { 0,                    false, true }, // XATTR_FILLBMP_STRETCH
        { 0,                    false, true }, // XATTR_FILLBMP_POSOFFSETX
        { 0,                    false, true }, // XATTR_FILLBMP_POSOFFSETY
        { 0,                    false, true }, // XATTR_FILLBACKGROUND
        { SID_ATTR_METRIC,      false, true }
    };

    MeasurementSystem eSystem = SvtSysLocale().GetLocaleData().getMeasurementSystemEnum();
@@ -4189,7 +4190,8 @@ void OReportController::openZoomDialog()

    static SfxItemInfo aItemInfos[] =
    {
        { SID_ATTR_ZOOM, true }
        // _nSID, _bNeedsPoolRegistration, _bShareable
        { SID_ATTR_ZOOM, false, true }
    };
    std::vector<SfxPoolItem*> pDefaults
    {
diff --git a/sc/inc/attarray.hxx b/sc/inc/attarray.hxx
index 521f3b7..0d2457c 100644
--- a/sc/inc/attarray.hxx
+++ b/sc/inc/attarray.hxx
@@ -84,7 +84,7 @@ struct ScAttrEntry
    const ScPatternAttr*    pPattern;
    bool operator==( const ScAttrEntry& other ) const
    {
        return nEndRow == other.nEndRow && pPattern == other.pPattern;
        return nEndRow == other.nEndRow && SfxPoolItem::areSame(pPattern, other.pPattern);
    }
};

diff --git a/sc/inc/attrib.hxx b/sc/inc/attrib.hxx
index dc394df..ec004f3 100644
--- a/sc/inc/attrib.hxx
+++ b/sc/inc/attrib.hxx
@@ -280,8 +280,6 @@ public:
    virtual ~ScCondFormatItem() override;

    virtual bool operator==(const SfxPoolItem& rCmp ) const override;
    virtual bool            operator<(const SfxPoolItem& rCmp) const override;
    virtual bool            IsSortable() const override { return true; }
    virtual ScCondFormatItem*  Clone( SfxItemPool* = nullptr ) const override;

    const ScCondFormatIndexes& GetCondFormatData() const { return maIndex;}
diff --git a/sc/inc/docpool.hxx b/sc/inc/docpool.hxx
index 9280fb3..c73d034 100644
--- a/sc/inc/docpool.hxx
+++ b/sc/inc/docpool.hxx
@@ -47,7 +47,8 @@ public:
                                  OUString&           rText,
                                  const IntlWrapper& rIntl ) const override;
private:
    virtual const SfxPoolItem&  PutImpl( const SfxPoolItem&, sal_uInt16 nWhich = 0, bool bPassingOwnership = false ) override;
    virtual void newItem_Callback(const SfxPoolItem& rItem) const override;
    virtual bool newItem_UseDirect(const SfxPoolItem& rItem) const override;
};

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/inc/patattr.hxx b/sc/inc/patattr.hxx
index eacb69f..b5deb19 100644
--- a/sc/inc/patattr.hxx
+++ b/sc/inc/patattr.hxx
@@ -56,7 +56,7 @@ class SC_DLLPUBLIC ScPatternAttr final : public SfxSetItem
    mutable std::optional<sal_uInt32> mxHashCode;
    mutable std::optional<bool> mxVisible;
    ScStyleSheet*              pStyle;
    sal_uInt64                 mnKey;
    sal_uInt64                 mnPAKey;
public:
                            ScPatternAttr(SfxItemSet&& pItemSet, const OUString& rStyleName);
                            ScPatternAttr(SfxItemSet&& pItemSet);
@@ -66,9 +66,6 @@ public:
    virtual ScPatternAttr*  Clone( SfxItemPool *pPool = nullptr ) const override;

    virtual bool            operator==(const SfxPoolItem& rCmp) const override;
    // Class cannot be IsSortable() because it's mutable, implement at least Lookup().
    virtual bool            HasLookup() const override { return true; }
    virtual lookup_iterator Lookup(lookup_iterator begin, lookup_iterator end ) const override;

    const SfxPoolItem&      GetItem( sal_uInt16 nWhichP ) const
                                        { return GetItemSet().Get(nWhichP); }
@@ -181,8 +178,8 @@ public:
    Degree100               GetRotateVal( const SfxItemSet* pCondSet ) const;
    ScRotateDir             GetRotateDir( const SfxItemSet* pCondSet ) const;

    void                    SetKey(sal_uInt64 nKey);
    sal_uInt64              GetKey() const;
    void                    SetPAKey(sal_uInt64 nKey);
    sal_uInt64              GetPAKey() const;

    static std::optional<bool> FastEqualPatternSets( const SfxItemSet& rSet1, const SfxItemSet& rSet2 );

diff --git a/sc/qa/unit/ucalc.cxx b/sc/qa/unit/ucalc.cxx
index c7bfc3e..a3e2d2d 100644
--- a/sc/qa/unit/ucalc.cxx
+++ b/sc/qa/unit/ucalc.cxx
@@ -1211,7 +1211,7 @@ CPPUNIT_TEST_FIXTURE(Test, testHorizontalAttrIterator)
        size_t nCheckPos = 0;
        for (const ScPatternAttr* pAttr = aIter.GetNext(nCol1, nCol2, nRow); pAttr; pAttr = aIter.GetNext(nCol1, nCol2, nRow))
        {
            if( pAttr == m_pDoc->GetDefPattern())
            if (SfxPoolItem::areSame( pAttr, m_pDoc->GetDefPattern()))
                continue;
            CPPUNIT_ASSERT_MESSAGE("Iteration longer than expected.", nCheckPos < nCheckLen);
            CPPUNIT_ASSERT_EQUAL(aChecks[nCheckPos][0], static_cast<int>(nCol1));
@@ -1302,7 +1302,7 @@ CPPUNIT_TEST_FIXTURE(Test, testIteratorsDefPattern)
    CPPUNIT_ASSERT_EQUAL(SCCOL(102 + 1), m_pDoc->GetAllocatedColumnsCount(0));
    const ScPatternAttr* pattern = m_pDoc->GetPattern(100, 0, 0);
    const ScPatternAttr* defPattern = m_pDoc->GetDefPattern();
    CPPUNIT_ASSERT(pattern != defPattern);
    CPPUNIT_ASSERT(!SfxPoolItem::areSame(pattern, defPattern));
    CPPUNIT_ASSERT_EQUAL(pattern, m_pDoc->GetPattern(102, 0, 0));
    CPPUNIT_ASSERT_EQUAL(defPattern, m_pDoc->GetPattern(101, 0, 0));
    CPPUNIT_ASSERT_EQUAL(defPattern, m_pDoc->GetPattern(103, 0, 0));
diff --git a/sc/source/core/data/attarray.cxx b/sc/source/core/data/attarray.cxx
index b6d062b..3e56226 100644
--- a/sc/source/core/data/attarray.cxx
+++ b/sc/source/core/data/attarray.cxx
@@ -63,7 +63,7 @@ ScAttrArray::ScAttrArray( SCCOL nNewCol, SCTAB nNewTab, ScDocument& rDoc, ScAttr
    {
        mvData[nIdx].nEndRow = pDefaultColAttrArray->mvData[nIdx].nEndRow;
        ScPatternAttr aNewPattern( *(pDefaultColAttrArray->mvData[nIdx].pPattern) );
        mvData[nIdx].pPattern = &rDocument.GetPool()->Put( aNewPattern );
        mvData[nIdx].pPattern = &rDocument.GetPool()->DirectPutItemInPool( aNewPattern );
        bool bNumFormatChanged = false;
        if ( ScGlobal::CheckWidthInvalidate( bNumFormatChanged,
             mvData[nIdx].pPattern->GetItemSet(), rDocument.GetDefPattern()->GetItemSet() ) )
@@ -83,7 +83,7 @@ ScAttrArray::~ScAttrArray()

    ScDocumentPool* pDocPool = rDocument.GetPool();
    for (auto const & rEntry : mvData)
        pDocPool->Remove(*rEntry.pPattern);
        pDocPool->DirectRemoveItemFromPool(*rEntry.pPattern);
}

#if DEBUG_SC_TESTATTRARRAY
@@ -140,14 +140,14 @@ void ScAttrArray::Reset( const ScPatternAttr* pPattern )
                rDocument.InvalidateTextWidth( &aAdrStart, &aAdrEnd, bNumFormatChanged );
            }
        }
        pDocPool->Remove(*pOldPattern);
        pDocPool->DirectRemoveItemFromPool(*pOldPattern);
    }
    mvData.resize(0);

    rDocument.SetStreamValid(nTab, false);

    mvData.resize(1);
    const ScPatternAttr* pNewPattern = &pDocPool->Put(*pPattern);
    const ScPatternAttr* pNewPattern = &pDocPool->DirectPutItemInPool(*pPattern);
    mvData[0].nEndRow = rDocument.MaxRow();
    mvData[0].pPattern = pNewPattern;
}
@@ -159,10 +159,10 @@ bool ScAttrArray::Concat(SCSIZE nPos)
    {
        if (nPos > 0)
        {
            if (mvData[nPos - 1].pPattern == mvData[nPos].pPattern)
            if (SfxPoolItem::areSame(mvData[nPos - 1].pPattern, mvData[nPos].pPattern))
            {
                mvData[nPos - 1].nEndRow = mvData[nPos].nEndRow;
                rDocument.GetPool()->Remove(*mvData[nPos].pPattern);
                rDocument.GetPool()->DirectRemoveItemFromPool(*mvData[nPos].pPattern);
                mvData.erase(mvData.begin() + nPos);
                nPos--;
                bRet = true;
@@ -170,10 +170,10 @@ bool ScAttrArray::Concat(SCSIZE nPos)
        }
        if (nPos + 1 < mvData.size())
        {
            if (mvData[nPos + 1].pPattern == mvData[nPos].pPattern)
            if (SfxPoolItem::areSame(mvData[nPos + 1].pPattern, mvData[nPos].pPattern))
            {
                mvData[nPos].nEndRow = mvData[nPos + 1].nEndRow;
                rDocument.GetPool()->Remove(*mvData[nPos].pPattern);
                rDocument.GetPool()->DirectRemoveItemFromPool(*mvData[nPos].pPattern);
                mvData.erase(mvData.begin() + nPos + 1);
                bRet = true;
            }
@@ -459,9 +459,9 @@ const ScPatternAttr* ScAttrArray::SetPatternAreaImpl(SCROW nStartRow, SCROW nEnd
        if (bPutToPool)
        {
            if (bPassingOwnership)
                pPattern = &rDocument.GetPool()->Put(std::unique_ptr<ScPatternAttr>(const_cast<ScPatternAttr*>(pPattern)));
                pPattern = &rDocument.GetPool()->DirectPutItemInPool(std::unique_ptr<ScPatternAttr>(const_cast<ScPatternAttr*>(pPattern)));
            else
                pPattern = &rDocument.GetPool()->Put(*pPattern);
                pPattern = &rDocument.GetPool()->DirectPutItemInPool(*pPattern);
        }
        if ((nStartRow == 0) && (nEndRow == rDocument.MaxRow()))
            Reset(pPattern);
@@ -520,7 +520,7 @@ const ScPatternAttr* ScAttrArray::SetPatternAreaImpl(SCROW nStartRow, SCROW nEnd
            if ( nStartRow > 0 )
            {
                nInsert = rDocument.MaxRow() + 1;
                if ( mvData[ni].pPattern != pPattern )
                if ( !SfxPoolItem::areSame(mvData[ni].pPattern, pPattern ) )
                {
                    if ( ni == 0 || (mvData[ni-1].nEndRow < nStartRow - 1) )
                    {   // may be a split or a simple insert or just a shrink,
@@ -533,7 +533,7 @@ const ScPatternAttr* ScAttrArray::SetPatternAreaImpl(SCROW nStartRow, SCROW nEnd
                    else if (mvData[ni - 1].nEndRow == nStartRow - 1)
                        nInsert = ni;
                }
                if ( ni > 0 && mvData[ni-1].pPattern == pPattern )
                if ( ni > 0 && SfxPoolItem::areSame(mvData[ni-1].pPattern, pPattern) )
                {   // combine
                    mvData[ni-1].nEndRow = nEndRow;
                    nInsert = rDocument.MaxRow() + 1;
@@ -548,11 +548,11 @@ const ScPatternAttr* ScAttrArray::SetPatternAreaImpl(SCROW nStartRow, SCROW nEnd
                nj++;
            if ( !bSplit )
            {
                if ( nj < mvData.size() && mvData[nj].pPattern == pPattern )
                if ( nj < mvData.size() && SfxPoolItem::areSame(mvData[nj].pPattern, pPattern ) )
                {   // combine
                    if ( ni > 0 )
                    {
                        if ( mvData[ni-1].pPattern == pPattern )
                        if ( SfxPoolItem::areSame(mvData[ni-1].pPattern, pPattern ) )
                        {   // adjacent entries
                            mvData[ni-1].nEndRow = mvData[nj].nEndRow;
                            nj++;
@@ -569,13 +569,13 @@ const ScPatternAttr* ScAttrArray::SetPatternAreaImpl(SCROW nStartRow, SCROW nEnd
            ScDocumentPool* pDocPool = rDocument.GetPool();
            if ( bSplit )
            {   // duplicate split entry in pool
                pDocPool->Put( *mvData[ni-1].pPattern );
                pDocPool->DirectPutItemInPool( *mvData[ni-1].pPattern );
            }
            if ( ni < nj )
            {   // remove middle entries
                for ( SCSIZE nk=ni; nk<nj; nk++)
                {   // remove entries from pool
                    pDocPool->Remove( *mvData[nk].pPattern );
                    pDocPool->DirectRemoveItemFromPool( *mvData[nk].pPattern );
                }
                if ( !bCombined )
                {   // replace one entry
@@ -681,8 +681,8 @@ void ScAttrArray::ApplyStyleArea( SCROW nStartRow, SCROW nEndRow, const ScStyleS
                }
            }

            rDocument.GetPool()->Remove(*mvData[nPos].pPattern);
            mvData[nPos].pPattern = &rDocument.GetPool()->Put(*pNewPattern);
            rDocument.GetPool()->DirectRemoveItemFromPool(*mvData[nPos].pPattern);
            mvData[nPos].pPattern = &rDocument.GetPool()->DirectPutItemInPool(*pNewPattern);
            if (Concat(nPos))
                Search(nStart, nPos);
            else
@@ -818,9 +818,9 @@ void ScAttrArray::ApplyLineStyleArea( SCROW nStartRow, SCROW nEndRow,
            else
            {
                // remove from pool ?
                rDocument.GetPool()->Remove(*mvData[nPos].pPattern);
                rDocument.GetPool()->DirectRemoveItemFromPool(*mvData[nPos].pPattern);
                mvData[nPos].pPattern =
                            &rDocument.GetPool()->Put(std::move(pNewPattern));
                            &rDocument.GetPool()->DirectPutItemInPool(std::move(pNewPattern));

                if (Concat(nPos))
                    Search(nStart, nPos);
@@ -862,7 +862,7 @@ void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCac
    {
        const ScPatternAttr* pOldPattern = mvData[nPos].pPattern;
        const ScPatternAttr* pNewPattern = static_cast<const ScPatternAttr*>( &pCache->ApplyTo( *pOldPattern ) );
        if (pNewPattern != pOldPattern)
        if (!SfxPoolItem::areSame(pNewPattern, pOldPattern))
        {
            SCROW nY1 = nStart;
            SCROW nY2 = mvData[nPos].nEndRow;
@@ -897,7 +897,7 @@ void ScAttrArray::ApplyCacheArea( SCROW nStartRow, SCROW nEndRow, SfxItemPoolCac
                    }
                }

                rDocument.GetPool()->Remove(*mvData[nPos].pPattern);
                rDocument.GetPool()->DirectRemoveItemFromPool(*mvData[nPos].pPattern);
                mvData[nPos].pPattern = pNewPattern;
                if (Concat(nPos))
                    Search(nStart, nPos);
@@ -924,7 +924,7 @@ void ScAttrArray::SetAttrEntries(std::vector<ScAttrEntry> && vNewData)
{
    ScDocumentPool* pDocPool = rDocument.GetPool();
    for (auto const & rEntry : mvData)
        pDocPool->Remove(*rEntry.pPattern);
        pDocPool->DirectRemoveItemFromPool(*rEntry.pPattern);

    mvData = std::move(vNewData);

@@ -961,7 +961,7 @@ static void lcl_MergeDeep( SfxItemSet& rMergeSet, const SfxItemSet& rSource )
            SfxItemState eNewState = rSource.GetItemState( nId, true, &pNewItem );
            if ( eNewState == SfxItemState::SET )
            {
                if ( pNewItem != pOldItem ) // Both pulled
                if ( !SfxPoolItem::areSame(pNewItem, pOldItem) ) // Both pulled
                    rMergeSet.InvalidateItem( nId );
            }
            else // Default
@@ -996,7 +996,7 @@ void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow,
            pPattern = mvData[nPos].pPattern;
        else
            pPattern = rDocument.GetDefPattern();
        if ( pPattern != rState.pOld1 && pPattern != rState.pOld2 )
        if ( !SfxPoolItem::areSame(pPattern, rState.pOld1) && !SfxPoolItem::areSame(pPattern, rState.pOld2) )
        {
            const SfxItemSet& rThisSet = pPattern->GetItemSet();
            if (rState.pItemSet)
@@ -1012,7 +1012,7 @@ void ScAttrArray::MergePatternArea( SCROW nStartRow, SCROW nEndRow,
                // first pattern - copied from parent
                rState.pItemSet.emplace( *rThisSet.GetPool(), rThisSet.GetRanges() );
                rState.pItemSet->Set( rThisSet, bDeep );
                rState.mnPatternId = pPattern->GetKey();
                rState.mnPatternId = pPattern->GetPAKey();
            }

            rState.pOld2 = rState.pOld1;
@@ -1585,7 +1585,7 @@ void ScAttrArray::SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow,
    while ( nThisRow <= nEndRow )
    {
        pOldPattern = mvData[nIndex].pPattern;
        if (pOldPattern != pWantedPattern) // FIXME: else-branch?
        if (!SfxPoolItem::areSame(pOldPattern, pWantedPattern)) // FIXME: else-branch?
        {
            if (nThisRow < nStartRow) nThisRow = nStartRow;
            nRow = mvData[nIndex].nEndRow;
@@ -1610,7 +1610,7 @@ void ScAttrArray::SetPatternAreaSafe( SCROW nStartRow, SCROW nEndRow,
                        bFirstUse = false;
                    else
                        // it's in the pool
                        rDocument.GetPool()->Put( *pWantedPattern );
                        rDocument.GetPool()->DirectPutItemInPool( *pWantedPattern );
                }
                SetPatternArea( nThisRow, nAttrRow, pWantedPattern );
            }
@@ -1843,13 +1843,13 @@ void ScAttrArray::FindStyleSheet( const SfxStyleSheetBase* pStyleSheet, ScFlatBo
            if (bReset)
            {
                ScPatternAttr aNewPattern(*mvData[nPos].pPattern);
                rDocument.GetPool()->Remove(*mvData[nPos].pPattern);
                rDocument.GetPool()->DirectRemoveItemFromPool(*mvData[nPos].pPattern);
                aNewPattern.SetStyleSheet( static_cast<ScStyleSheet*>(
                    rDocument.GetStyleSheetPool()->
                        Find( ScResId(STR_STYLENAME_STANDARD),
                              SfxStyleFamily::Para,
                              SfxStyleSearchBits::Auto | SfxStyleSearchBits::ScStandard ) ) );
                mvData[nPos].pPattern = &rDocument.GetPool()->Put(aNewPattern);
                mvData[nPos].pPattern = &rDocument.GetPool()->DirectPutItemInPool(aNewPattern);

                if (Concat(nPos))
                {
@@ -1904,7 +1904,7 @@ bool ScAttrArray::IsEmpty() const

    if (mvData.size() == 1)
    {
        return mvData[0].pPattern == rDocument.GetDefPattern();
        return SfxPoolItem::areSame(mvData[0].pPattern, rDocument.GetDefPattern());
    }
    else
        return false;
@@ -2043,7 +2043,7 @@ bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
    {
        const ScPatternAttr* pDefPattern1 = rDocument.GetDefPattern();
        const ScPatternAttr* pDefPattern2 = rOther.rDocument.GetDefPattern();
        return ( pDefPattern1 == pDefPattern2 || pDefPattern1->IsVisibleEqual( *pDefPattern2 ) );
        return ( SfxPoolItem::areSame(pDefPattern1, pDefPattern2) || pDefPattern1->IsVisibleEqual( *pDefPattern2 ) );
    }

    {
@@ -2073,7 +2073,7 @@ bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
            while ( nPos < pNonDefault->Count() && bEqual )
            {
                const ScPatternAttr* pNonDefPattern = pNonDefault->mvData[nPos].pPattern;
                bEqual = ( pNonDefPattern == pDefPattern ||
                bEqual = ( SfxPoolItem::areSame(pNonDefPattern, pDefPattern) ||
                           pNonDefPattern->IsVisibleEqual( *pDefPattern ) );

                if ( pNonDefault->mvData[nPos].nEndRow >= nEndRow ) break;
@@ -2098,7 +2098,7 @@ bool ScAttrArray::IsVisibleEqual( const ScAttrArray& rOther,
        SCROW nOtherRow = rOther.mvData[nOtherPos].nEndRow;
        const ScPatternAttr* pThisPattern = mvData[nThisPos].pPattern;
        const ScPatternAttr* pOtherPattern = rOther.mvData[nOtherPos].pPattern;
        bEqual = ( pThisPattern == pOtherPattern ||
        bEqual = ( SfxPoolItem::areSame(pThisPattern, pOtherPattern) ||
                    pThisPattern->IsVisibleEqual(*pOtherPattern) );

        if ( nThisRow >= nOtherRow )
@@ -2123,7 +2123,7 @@ bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW 
    {
        const ScPatternAttr* pDefPattern1 = rDocument.GetDefPattern();
        const ScPatternAttr* pDefPattern2 = rOther.rDocument.GetDefPattern();
        return ( pDefPattern1 == pDefPattern2 );
        return SfxPoolItem::areSame(pDefPattern1, pDefPattern2);
    }

    {
@@ -2153,7 +2153,7 @@ bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW 
            while ( nPos < pNonDefault->Count() && bEqual )
            {
                const ScPatternAttr* pNonDefPattern = pNonDefault->mvData[nPos].pPattern;
                bEqual = ( pNonDefPattern == pDefPattern );
                bEqual = SfxPoolItem::areSame( pNonDefPattern, pDefPattern );

                if ( pNonDefault->mvData[nPos].nEndRow >= nEndRow ) break;
                ++nPos;
@@ -2177,7 +2177,7 @@ bool ScAttrArray::IsAllEqual( const ScAttrArray& rOther, SCROW nStartRow, SCROW 
        SCROW nOtherRow = rOther.mvData[nOtherPos].nEndRow;
        const ScPatternAttr* pThisPattern = mvData[nThisPos].pPattern;
        const ScPatternAttr* pOtherPattern = rOther.mvData[nOtherPos].pPattern;
        bEqual = ( pThisPattern == pOtherPattern );
        bEqual = SfxPoolItem::areSame( pThisPattern, pOtherPattern );

        if ( nThisRow >= nOtherRow )
        {
@@ -2323,7 +2323,7 @@ void ScAttrArray::DeleteRow( SCROW nStartRow, SCSIZE nSize )
        {
            DeleteRange( nStartIndex, nEndIndex );
            if (nStartIndex > 0)
                if ( mvData[nStartIndex-1].pPattern == mvData[nStartIndex].pPattern )
                if ( SfxPoolItem::areSame( mvData[nStartIndex-1].pPattern, mvData[nStartIndex].pPattern ) )
                    DeleteRange( nStartIndex-1, nStartIndex-1 );
        }
    }
@@ -2341,7 +2341,7 @@ void ScAttrArray::DeleteRange( SCSIZE nStartIndex, SCSIZE nEndIndex )
    SetDefaultIfNotInit();
    ScDocumentPool* pDocPool = rDocument.GetPool();
    for (SCSIZE i = nStartIndex; i <= nEndIndex; i++)
        pDocPool->Remove(*mvData[i].pPattern);
        pDocPool->DirectRemoveItemFromPool(*mvData[i].pPattern);

    mvData.erase(mvData.begin() + nStartIndex, mvData.begin() + nEndIndex + 1);
}
@@ -2468,14 +2468,14 @@ void ScAttrArray::CopyArea(
                    aTmpPattern.GetItemSet().ClearItem( ATTR_MERGE_FLAG );

                if (bSamePool)
                    pNewPattern = &pDestDocPool->Put(aTmpPattern);
                    pNewPattern = &pDestDocPool->DirectPutItemInPool(aTmpPattern);
                else
                    pNewPattern = aTmpPattern.PutInPool( &rAttrArray.rDocument, &rDocument );
            }
            else
            {
                if (bSamePool)
                    pNewPattern = &pDestDocPool->Put(*pOldPattern);
                    pNewPattern = &pDestDocPool->DirectPutItemInPool(*pOldPattern);
                else
                    pNewPattern = pOldPattern->PutInPool( &rAttrArray.rDocument, &rDocument );
            }
@@ -2516,7 +2516,7 @@ void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, tools::Long nDy,
    {
        const ScPatternAttr* pNewPattern;
        if (bSamePool)
            pNewPattern = &pDestDocPool->Put(*rDocument.GetDefPattern());
            pNewPattern = &pDestDocPool->DirectPutItemInPool(*rDocument.GetDefPattern());
        else
            pNewPattern = rDocument.GetDefPattern()->PutInPool( &rAttrArray.rDocument, &rDocument );

@@ -2533,7 +2533,7 @@ void ScAttrArray::CopyAreaSafe( SCROW nStartRow, SCROW nEndRow, tools::Long nDy,
            const ScPatternAttr* pNewPattern;

            if (bSamePool)
                pNewPattern = &pDestDocPool->Put(*pOldPattern);
                pNewPattern = &pDestDocPool->DirectPutItemInPool(*pOldPattern);
            else
                pNewPattern = pOldPattern->PutInPool( &rAttrArray.rDocument, &rDocument );

diff --git a/sc/source/core/data/attrib.cxx b/sc/source/core/data/attrib.cxx
index efe494c..1a587d2 100644
--- a/sc/source/core/data/attrib.cxx
+++ b/sc/source/core/data/attrib.cxx
@@ -733,21 +733,6 @@ bool ScCondFormatItem::operator==( const SfxPoolItem& rCmp ) const
        && memcmp(&maIndex.front(), &other.maIndex.front(), maIndex.size() * sizeof(sal_uInt32)) == 0;
}

bool ScCondFormatItem::operator<( const SfxPoolItem& rCmp ) const
{
    auto const & other = static_cast<const ScCondFormatItem&>(rCmp);
    if ( maIndex.size() < other.maIndex.size() )
        return true;
    if ( maIndex.size() > other.maIndex.size() )
        return false;
    if (maIndex.empty() && other.maIndex.empty())
        return false;
    // memcmp is faster than operator< on std::vector
    // Note that on little-endian this results in a confusing ordering (256 < 1),
    // which technically doesn't matter as the ordering may be arbitrary.
    return memcmp(&maIndex.front(), &other.maIndex.front(), maIndex.size() * sizeof(sal_uInt32)) < 0;
}

ScCondFormatItem* ScCondFormatItem::Clone(SfxItemPool*) const
{
    return new ScCondFormatItem(maIndex);
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index 7ffd5ae..c448f79 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -476,7 +476,7 @@ void ScColumn::ApplyPattern( SCROW nRow, const ScPatternAttr& rPatAttr )

    const ScPatternAttr* pNewPattern = static_cast<const ScPatternAttr*>( &aCache.ApplyTo( *pPattern ) );

    if (pNewPattern != pPattern)
    if (!SfxPoolItem::areSame(pNewPattern, pPattern))
      pAttrArray->SetPattern( nRow, pNewPattern );
}

@@ -628,12 +628,12 @@ void ScColumn::ApplyAttr( SCROW nRow, const SfxPoolItem& rAttr )
    const ScPatternAttr* pOldPattern = pAttrArray->GetPattern( nRow );
    ScPatternAttr aTemp(*pOldPattern);
    aTemp.GetItemSet().Put(rAttr);
    const ScPatternAttr* pNewPattern = &pDocPool->Put( aTemp );
    const ScPatternAttr* pNewPattern = &pDocPool->DirectPutItemInPool( aTemp );

    if ( pNewPattern != pOldPattern )
    if (!SfxPoolItem::areSame( pNewPattern, pOldPattern ))
        pAttrArray->SetPattern( nRow, pNewPattern );
    else
        pDocPool->Remove( *pNewPattern );       // free up resources
        pDocPool->DirectRemoveItemFromPool( *pNewPattern );       // free up resources
}

ScRefCellValue ScColumn::GetCellValue( SCROW nRow ) const
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index e7ca588..28d928c 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -203,7 +203,7 @@ tools::Long ScColumn::GetNeededSize(
        }
        if (bNumeric)
        {
            if (!bMayInvalidatePattern || pPattern == pOldPattern)
            if (!bMayInvalidatePattern || SfxPoolItem::areSame(pPattern, pOldPattern))
                bBreak = false;
            else
            {
@@ -772,7 +772,7 @@ sal_uInt16 ScColumn::GetOptimalColWidth(
            // Or again in case there was a leading sep=";" row or two header
            // rows..
            const ScPatternAttr* pNextPattern = GetPattern( ++nRow );
            if (pNextPattern != pPattern)
            if (!SfxPoolItem::areSame(pNextPattern, pPattern))
                nFormat = pNextPattern->GetNumberFormat( pFormatter );
        }
        OUString aLongStr;
@@ -830,7 +830,7 @@ sal_uInt16 ScColumn::GetOptimalColWidth(

                    const ScPatternAttr* pPattern = GetPattern(nRow);
                    aOptions.pPattern = pPattern;
                    aOptions.bGetFont = (pPattern != pOldPattern || nScript != SvtScriptType::NONE);
                    aOptions.bGetFont = (!SfxPoolItem::areSame(pPattern, pOldPattern) || nScript != SvtScriptType::NONE);
                    pOldPattern = pPattern;
                    sal_uInt16 nThis = static_cast<sal_uInt16>(GetNeededSize(
                        nRow, pDev, nPPTX, nPPTY, rZoomX, rZoomY, true, aOptions, &pOldPattern));
@@ -1079,7 +1079,7 @@ void ScColumn::GetOptimalHeight(
                            if (nHeight > rHeights.GetValue(nRow))
                                rHeights.SetValue(nRow, nRow, nHeight);
                            // Pattern changed due to calculation? => sync.
                            if (pPattern != pOldPattern)
                            if (!SfxPoolItem::areSame(pPattern, pOldPattern))
                            {
                                pPattern = aIter.Resync( nRow, nStart, nEnd);
                                nNextEnd = 0;
diff --git a/sc/source/core/data/column4.cxx b/sc/source/core/data/column4.cxx
index 8e22b13..324e54b 100644
--- a/sc/source/core/data/column4.cxx
+++ b/sc/source/core/data/column4.cxx
@@ -1248,10 +1248,10 @@ void ScColumn::Swap( ScColumn& rOther, SCROW nRow1, SCROW nRow2, bool bPattern )
        {
            const ScPatternAttr* pPat1 = GetPattern(nRow);
            const ScPatternAttr* pPat2 = rOther.GetPattern(nRow);
            if (pPat1 != pPat2)
            if (!SfxPoolItem::areSame(pPat1, pPat2))
            {
                if (pPat1->GetRefCount() == 1)
                    pPat1 = &rOther.GetDoc().GetPool()->Put(*pPat1);
                    pPat1 = &rOther.GetDoc().GetPool()->DirectPutItemInPool(*pPat1);
                SetPattern(nRow, *pPat2);
                rOther.SetPattern(nRow, *pPat1);
            }
diff --git a/sc/source/core/data/dociter.cxx b/sc/source/core/data/dociter.cxx
index 5c0f098..35c0d2c 100644
--- a/sc/source/core/data/dociter.cxx
+++ b/sc/source/core/data/dociter.cxx
@@ -1424,7 +1424,7 @@ void ScHorizontalAttrIterator::InitForNextRow(bool bInitialization)
            nMinNextEnd = pNextEnd[nPos];

        // store positions of ScHorizontalAttrIterator elements (minimizing expensive ScPatternAttr comparisons)
        if (i > nStartCol && ppPatterns[nThisHead] != ppPatterns[nPos])
        if (i > nStartCol && !SfxPoolItem::areSame(ppPatterns[nThisHead], ppPatterns[nPos]))
        {
           pHorizEnd[nThisHead] = i - 1;
           nThisHead = nPos; // start position of the next horizontal group
diff --git a/sc/source/core/data/docpool.cxx b/sc/source/core/data/docpool.cxx
index 47c485e..05dd889 100644
--- a/sc/source/core/data/docpool.cxx
+++ b/sc/source/core/data/docpool.cxx
@@ -88,96 +88,97 @@ SvxFontItem* getDefaultFontItem(LanguageType eLang, DefaultFontType nFontType, s

SfxItemInfo const  aItemInfos[] =
{
    { SID_ATTR_CHAR_FONT,           true },    // ATTR_FONT
    { SID_ATTR_CHAR_FONTHEIGHT,     true },    // ATTR_FONT_HEIGHT
    { SID_ATTR_CHAR_WEIGHT,         true },    // ATTR_FONT_WEIGHT
    { SID_ATTR_CHAR_POSTURE,        true },    // ATTR_FONT_POSTURE
    { SID_ATTR_CHAR_UNDERLINE,      true },    // ATTR_FONT_UNDERLINE
    { SID_ATTR_CHAR_OVERLINE,       true },    // ATTR_FONT_OVERLINE
    { SID_ATTR_CHAR_STRIKEOUT,      true },    // ATTR_FONT_CROSSEDOUT
    { SID_ATTR_CHAR_CONTOUR,        true },    // ATTR_FONT_CONTOUR
    { SID_ATTR_CHAR_SHADOWED,       true },    // ATTR_FONT_SHADOWED
    { SID_ATTR_CHAR_COLOR,          true },    // ATTR_FONT_COLOR
    { SID_ATTR_CHAR_LANGUAGE,       true },    // ATTR_FONT_LANGUAGE
    { SID_ATTR_CHAR_CJK_FONT,       true },    // ATTR_CJK_FONT            from 614
    { SID_ATTR_CHAR_CJK_FONTHEIGHT, true },    // ATTR_CJK_FONT_HEIGHT     from 614
    { SID_ATTR_CHAR_CJK_WEIGHT,     true },    // ATTR_CJK_FONT_WEIGHT     from 614
    { SID_ATTR_CHAR_CJK_POSTURE,    true },    // ATTR_CJK_FONT_POSTURE    from 614
    { SID_ATTR_CHAR_CJK_LANGUAGE,   true },    // ATTR_CJK_FONT_LANGUAGE   from 614
    { SID_ATTR_CHAR_CTL_FONT,       true },    // ATTR_CTL_FONT            from 614
    { SID_ATTR_CHAR_CTL_FONTHEIGHT, true },    // ATTR_CTL_FONT_HEIGHT     from 614
    { SID_ATTR_CHAR_CTL_WEIGHT,     true },    // ATTR_CTL_FONT_WEIGHT     from 614
    { SID_ATTR_CHAR_CTL_POSTURE,    true },    // ATTR_CTL_FONT_POSTURE    from 614
    { SID_ATTR_CHAR_CTL_LANGUAGE,   true },    // ATTR_CTL_FONT_LANGUAGE   from 614
    { SID_ATTR_CHAR_EMPHASISMARK,   true },    // ATTR_FONT_EMPHASISMARK   from 614
    { 0,                            true },    // ATTR_USERDEF             from 614 / 641c
    { SID_ATTR_CHAR_WORDLINEMODE,   true },    // ATTR_FONT_WORDLINE       from 632b
    { SID_ATTR_CHAR_RELIEF,         true },    // ATTR_FONT_RELIEF         from 632b
    { SID_ATTR_ALIGN_HYPHENATION,   true },    // ATTR_HYPHENATE           from 632b
    { 0,                            true },    // ATTR_SCRIPTSPACE         from 614d
    { 0,                            true },    // ATTR_HANGPUNCTUATION     from 614d
    { SID_ATTR_PARA_FORBIDDEN_RULES,true },    // ATTR_FORBIDDEN_RULES     from 614d
    { SID_ATTR_ALIGN_HOR_JUSTIFY,   true },    // ATTR_HOR_JUSTIFY
    { SID_ATTR_ALIGN_HOR_JUSTIFY_METHOD, true }, // ATTR_HOR_JUSTIFY_METHOD
    { SID_ATTR_ALIGN_INDENT,        true },    // ATTR_INDENT          from 350
    { SID_ATTR_ALIGN_VER_JUSTIFY,   true },    // ATTR_VER_JUSTIFY
    { SID_ATTR_ALIGN_VER_JUSTIFY_METHOD, true }, // ATTR_VER_JUSTIFY_METHOD
    { SID_ATTR_ALIGN_STACKED,       true },    // ATTR_STACKED         from 680/dr14 (replaces ATTR_ORIENTATION)
    { SID_ATTR_ALIGN_DEGREES,       true },    // ATTR_ROTATE_VALUE    from 367
    { SID_ATTR_ALIGN_LOCKPOS,       true },    // ATTR_ROTATE_MODE     from 367
    { SID_ATTR_ALIGN_ASIANVERTICAL, true },    // ATTR_VERTICAL_ASIAN  from 642
    { SID_ATTR_FRAMEDIRECTION,      true },    // ATTR_WRITINGDIR      from 643
    { SID_ATTR_ALIGN_LINEBREAK,     true },    // ATTR_LINEBREAK
    { SID_ATTR_ALIGN_SHRINKTOFIT,   true },    // ATTR_SHRINKTOFIT     from 680/dr14
    { SID_ATTR_BORDER_DIAG_TLBR,    true },    // ATTR_BORDER_TLBR     from 680/dr14
    { SID_ATTR_BORDER_DIAG_BLTR,    true },    // ATTR_BORDER_BLTR     from 680/dr14
    { SID_ATTR_ALIGN_MARGIN,        true },    // ATTR_MARGIN
    { 0,                            true },    // ATTR_MERGE
    { 0,                            true },    // ATTR_MERGE_FLAG
    { SID_ATTR_NUMBERFORMAT_VALUE,  true },    // ATTR_VALUE_FORMAT
    { 0,                            true },    // ATTR_LANGUAGE_FORMAT from 329, is combined with SID_ATTR_NUMBERFORMAT_VALUE in the dialog
    { SID_ATTR_BRUSH,               true },    // ATTR_BACKGROUND
    { SID_SCATTR_PROTECTION,        true },    // ATTR_PROTECTION
    { SID_ATTR_BORDER_OUTER,        true },    // ATTR_BORDER
    { SID_ATTR_BORDER_INNER,        true },    // ATTR_BORDER_INNER
    { SID_ATTR_BORDER_SHADOW,       true },    // ATTR_SHADOW
    { 0,                            true },    // ATTR_VALIDDATA
    { 0,                            true },    // ATTR_CONDITIONAL
    { 0,                            true },    // ATTR_HYPERLINK
    { 0,                            true },    // ATTR_PATTERN
    { SID_ATTR_LRSPACE,             true },    // ATTR_LRSPACE
    { SID_ATTR_ULSPACE,             true },    // ATTR_ULSPACE
    { SID_ATTR_PAGE,                true },    // ATTR_PAGE
    { SID_ATTR_PAGE_PAPERBIN,       true },    // ATTR_PAGE_PAPERBIN
    { SID_ATTR_PAGE_SIZE,           true },    // ATTR_PAGE_SIZE
    { SID_ATTR_PAGE_EXT1,           true },    // ATTR_PAGE_HORCENTER
    { SID_ATTR_PAGE_EXT2,           true },    // ATTR_PAGE_VERCENTER
    { SID_ATTR_PAGE_ON,             true },    // ATTR_PAGE_ON
    { SID_ATTR_PAGE_DYNAMIC,        true },    // ATTR_PAGE_DYNAMIC
    { SID_ATTR_PAGE_SHARED,         true },    // ATTR_PAGE_SHARED
    { SID_ATTR_PAGE_SHARED_FIRST,   true },    // ATTR_PAGE_SHARED_FIRST
    { 0,                            true },    // ATTR_PAGE_NOTES aka. SID_SCATTR_PAGE_NOTES
    { 0,                            true },    // ATTR_PAGE_GRID aka. SID_SCATTR_PAGE_GRID
    { 0,                            true },    // ATTR_PAGE_HEADERS aka. SID_SCATTR_PAGE_HEADERS
    { 0,                            true },    // ATTR_PAGE_CHARTS aka. SID_SCATTR_PAGE_CHARTS
    { 0,                            true },    // ATTR_PAGE_OBJECTS aka. SID_SCATTR_PAGE_OBJECTS
    { 0,                            true },    // ATTR_PAGE_DRAWINGS aka. SID_SCATTR_PAGE_DRAWINGS
    { 0,                            true },    // ATTR_PAGE_TOPDOWN aka. SID_SCATTR_PAGE_TOPDOWN
    { 0,                            true },    // ATTR_PAGE_SCALE aka SID_SCATTR_PAGE_SCALE
    { 0,                            true },    // ATTR_PAGE_SCALETOPAGES aka SID_SCATTR_PAGE_SCALETOPAGES
    { 0,                            true },    // ATTR_PAGE_FIRSTPAGENO aka SID_SCATTR_PAGE_FIRSTPAGENO
    { 0,                            true },    // ATTR_PAGE_HEADERLEFT aka SID_SCATTR_PAGE_HEADERLEFT
    { 0,                            true },    // ATTR_PAGE_FOOTERLEFT aka SID_SCATTR_PAGE_FOOTERLEFT
    { 0,                            true },    // ATTR_PAGE_HEADERRIGHT aka SID_SCATTR_PAGE_HEADERRIGHT
    { 0,                            true },    // ATTR_PAGE_FOOTERRIGHT aka. SID_SCATTR_PAGE_FOOTERRIGHT
    { 0,                            true },    // ATTR_PAGE_HEADERFIRST aka. SID_SCATTR_PAGE_HEADERFIRST
    { 0,                            true },    // ATTR_PAGE_FOOTERFIRST aka. SID_SCATTR_PAGE_FOOTERFIRST`
    { SID_ATTR_PAGE_HEADERSET,      true },    // ATTR_PAGE_HEADERSET
    { SID_ATTR_PAGE_FOOTERSET,      true },    // ATTR_PAGE_FOOTERSET
    { 0,                            true },    // ATTR_PAGE_FORMULAS aka. SID_SCATTR_PAGE_FORMULAS
    { 0,                            true },    // ATTR_PAGE_NULLVALS aka. SID_SCATTR_PAGE_NULLVALS
    { 0,                            true },    // ATTR_PAGE_SCALETO aka. SID_SCATTR_PAGE_SCALETO
    { 0,                            true }     // ATTR_HIDDEN
    // _nSID, _bNeedsPoolRegistration, _bShareable
    { SID_ATTR_CHAR_FONT,                   true,  true },    // ATTR_FONT
    { SID_ATTR_CHAR_FONTHEIGHT,             false, true },    // ATTR_FONT_HEIGHT
    { SID_ATTR_CHAR_WEIGHT,                 false, true },    // ATTR_FONT_WEIGHT
    { SID_ATTR_CHAR_POSTURE,                false, true },    // ATTR_FONT_POSTURE
    { SID_ATTR_CHAR_UNDERLINE,              false, true },    // ATTR_FONT_UNDERLINE
    { SID_ATTR_CHAR_OVERLINE,               false, true },    // ATTR_FONT_OVERLINE
    { SID_ATTR_CHAR_STRIKEOUT,              false, true },    // ATTR_FONT_CROSSEDOUT
    { SID_ATTR_CHAR_CONTOUR,                false, true },    // ATTR_FONT_CONTOUR
    { SID_ATTR_CHAR_SHADOWED,               false, true },    // ATTR_FONT_SHADOWED
    { SID_ATTR_CHAR_COLOR,                  true,  true },    // ATTR_FONT_COLOR
    { SID_ATTR_CHAR_LANGUAGE,               false, true },    // ATTR_FONT_LANGUAGE
    { SID_ATTR_CHAR_CJK_FONT,               true,  true },    // ATTR_CJK_FONT            from 614
    { SID_ATTR_CHAR_CJK_FONTHEIGHT,         false, true },    // ATTR_CJK_FONT_HEIGHT     from 614
    { SID_ATTR_CHAR_CJK_WEIGHT,             false, true },    // ATTR_CJK_FONT_WEIGHT     from 614
    { SID_ATTR_CHAR_CJK_POSTURE,            false, true },    // ATTR_CJK_FONT_POSTURE    from 614
    { SID_ATTR_CHAR_CJK_LANGUAGE,           false, true },    // ATTR_CJK_FONT_LANGUAGE   from 614
    { SID_ATTR_CHAR_CTL_FONT,               true,  true },    // ATTR_CTL_FONT            from 614
    { SID_ATTR_CHAR_CTL_FONTHEIGHT,         false, true },    // ATTR_CTL_FONT_HEIGHT     from 614
    { SID_ATTR_CHAR_CTL_WEIGHT,             false, true },    // ATTR_CTL_FONT_WEIGHT     from 614
    { SID_ATTR_CHAR_CTL_POSTURE,            false, true },    // ATTR_CTL_FONT_POSTURE    from 614
    { SID_ATTR_CHAR_CTL_LANGUAGE,           false, true },    // ATTR_CTL_FONT_LANGUAGE   from 614
    { SID_ATTR_CHAR_EMPHASISMARK,           false, true },    // ATTR_FONT_EMPHASISMARK   from 614
    { 0,                                    true,  true },    // ATTR_USERDEF             from 614 / 641c
    { SID_ATTR_CHAR_WORDLINEMODE,           false, true },    // ATTR_FONT_WORDLINE       from 632b
    { SID_ATTR_CHAR_RELIEF,                 false, true },    // ATTR_FONT_RELIEF         from 632b
    { SID_ATTR_ALIGN_HYPHENATION,           false, true },    // ATTR_HYPHENATE           from 632b
    { 0,                                    false, true },    // ATTR_SCRIPTSPACE         from 614d
    { 0,                                    false, true },    // ATTR_HANGPUNCTUATION     from 614d
    { SID_ATTR_PARA_FORBIDDEN_RULES,        false, true },    // ATTR_FORBIDDEN_RULES     from 614d
    { SID_ATTR_ALIGN_HOR_JUSTIFY,           false, true },    // ATTR_HOR_JUSTIFY
    { SID_ATTR_ALIGN_HOR_JUSTIFY_METHOD,    false, true }, // ATTR_HOR_JUSTIFY_METHOD
    { SID_ATTR_ALIGN_INDENT,                false, true },    // ATTR_INDENT          from 350
    { SID_ATTR_ALIGN_VER_JUSTIFY,           false, true },    // ATTR_VER_JUSTIFY
    { SID_ATTR_ALIGN_VER_JUSTIFY_METHOD,    false, true }, // ATTR_VER_JUSTIFY_METHOD
    { SID_ATTR_ALIGN_STACKED,               false, true },    // ATTR_STACKED         from 680/dr14 (replaces ATTR_ORIENTATION)
    { SID_ATTR_ALIGN_DEGREES,               true,  true },    // ATTR_ROTATE_VALUE    from 367
    { SID_ATTR_ALIGN_LOCKPOS,               false, true },    // ATTR_ROTATE_MODE     from 367
    { SID_ATTR_ALIGN_ASIANVERTICAL,         false, true },    // ATTR_VERTICAL_ASIAN  from 642
    { SID_ATTR_FRAMEDIRECTION,              false, true },    // ATTR_WRITINGDIR      from 643
    { SID_ATTR_ALIGN_LINEBREAK,             false, true },    // ATTR_LINEBREAK
    { SID_ATTR_ALIGN_SHRINKTOFIT,           false, true },    // ATTR_SHRINKTOFIT     from 680/dr14
    { SID_ATTR_BORDER_DIAG_TLBR,            false, true },    // ATTR_BORDER_TLBR     from 680/dr14
    { SID_ATTR_BORDER_DIAG_BLTR,            false, true },    // ATTR_BORDER_BLTR     from 680/dr14
    { SID_ATTR_ALIGN_MARGIN,                false, true },    // ATTR_MARGIN
    { 0,                                    false, true },    // ATTR_MERGE
    { 0,                                    false, true },    // ATTR_MERGE_FLAG
    { SID_ATTR_NUMBERFORMAT_VALUE,          false, true },    // ATTR_VALUE_FORMAT
    { 0,                                    false, true },    // ATTR_LANGUAGE_FORMAT from 329, is combined with SID_ATTR_NUMBERFORMAT_VALUE in the dialog
    { SID_ATTR_BRUSH,                       true,  true },    // ATTR_BACKGROUND
    { SID_SCATTR_PROTECTION,                false, true },    // ATTR_PROTECTION
    { SID_ATTR_BORDER_OUTER,                false, true },    // ATTR_BORDER
    { SID_ATTR_BORDER_INNER,                false, true },    // ATTR_BORDER_INNER
    { SID_ATTR_BORDER_SHADOW,               false, true },    // ATTR_SHADOW
    { 0,                                    false, true },    // ATTR_VALIDDATA
    { 0,                                    false, true },    // ATTR_CONDITIONAL
    { 0,                                    false, true },    // ATTR_HYPERLINK
    { 0,                                    true,  true },    // ATTR_PATTERN
    { SID_ATTR_LRSPACE,                     false, true },    // ATTR_LRSPACE
    { SID_ATTR_ULSPACE,                     false, true },    // ATTR_ULSPACE
    { SID_ATTR_PAGE,                        false, true },    // ATTR_PAGE
    { SID_ATTR_PAGE_PAPERBIN,               false, true },    // ATTR_PAGE_PAPERBIN
    { SID_ATTR_PAGE_SIZE,                   false, true },    // ATTR_PAGE_SIZE
    { SID_ATTR_PAGE_EXT1,                   false, true },    // ATTR_PAGE_HORCENTER
    { SID_ATTR_PAGE_EXT2,                   false, true },    // ATTR_PAGE_VERCENTER
    { SID_ATTR_PAGE_ON,                     false, true },    // ATTR_PAGE_ON
    { SID_ATTR_PAGE_DYNAMIC,                false, true },    // ATTR_PAGE_DYNAMIC
    { SID_ATTR_PAGE_SHARED,                 false, true },    // ATTR_PAGE_SHARED
    { SID_ATTR_PAGE_SHARED_FIRST,           false, true },    // ATTR_PAGE_SHARED_FIRST
    { 0,                                    false, true },    // ATTR_PAGE_NOTES aka. SID_SCATTR_PAGE_NOTES
    { 0,                                    false, true },    // ATTR_PAGE_GRID aka. SID_SCATTR_PAGE_GRID
    { 0,                                    false, true },    // ATTR_PAGE_HEADERS aka. SID_SCATTR_PAGE_HEADERS
    { 0,                                    false, true },    // ATTR_PAGE_CHARTS aka. SID_SCATTR_PAGE_CHARTS
    { 0,                                    false, true },    // ATTR_PAGE_OBJECTS aka. SID_SCATTR_PAGE_OBJECTS
    { 0,                                    false, true },    // ATTR_PAGE_DRAWINGS aka. SID_SCATTR_PAGE_DRAWINGS
    { 0,                                    false, true },    // ATTR_PAGE_TOPDOWN aka. SID_SCATTR_PAGE_TOPDOWN
    { 0,                                    false, true },    // ATTR_PAGE_SCALE aka SID_SCATTR_PAGE_SCALE
    { 0,                                    false, true },    // ATTR_PAGE_SCALETOPAGES aka SID_SCATTR_PAGE_SCALETOPAGES
    { 0,                                    false, true },    // ATTR_PAGE_FIRSTPAGENO aka SID_SCATTR_PAGE_FIRSTPAGENO
    { 0,                                    true,  true },    // ATTR_PAGE_HEADERLEFT aka SID_SCATTR_PAGE_HEADERLEFT
    { 0,                                    true,  true },    // ATTR_PAGE_FOOTERLEFT aka SID_SCATTR_PAGE_FOOTERLEFT
    { 0,                                    true,  true },    // ATTR_PAGE_HEADERRIGHT aka SID_SCATTR_PAGE_HEADERRIGHT
    { 0,                                    true,  true },    // ATTR_PAGE_FOOTERRIGHT aka. SID_SCATTR_PAGE_FOOTERRIGHT
    { 0,                                    true,  true },    // ATTR_PAGE_HEADERFIRST aka. SID_SCATTR_PAGE_HEADERFIRST
    { 0,                                    true,  true },    // ATTR_PAGE_FOOTERFIRST aka. SID_SCATTR_PAGE_FOOTERFIRST`
    { SID_ATTR_PAGE_HEADERSET,              false, true },    // ATTR_PAGE_HEADERSET
    { SID_ATTR_PAGE_FOOTERSET,              false, true },    // ATTR_PAGE_FOOTERSET
    { 0,                                    false, true },    // ATTR_PAGE_FORMULAS aka. SID_SCATTR_PAGE_FORMULAS
    { 0,                                    false, true },    // ATTR_PAGE_NULLVALS aka. SID_SCATTR_PAGE_NULLVALS
    { 0,                                    false, true },    // ATTR_PAGE_SCALETO aka. SID_SCATTR_PAGE_SCALETO
    { 0,                                    false, true }     // ATTR_HIDDEN
};
static_assert(
    SAL_N_ELEMENTS(aItemInfos) == ATTR_ENDINDEX - ATTR_STARTINDEX + 1, "these must match");
@@ -336,24 +337,20 @@ ScDocumentPool::~ScDocumentPool()
    }
}

const SfxPoolItem& ScDocumentPool::PutImpl( const SfxPoolItem& rItem, sal_uInt16 nWhich, bool bPassingOwnership )
void ScDocumentPool::newItem_Callback(const SfxPoolItem& rItem) const
{
    if ( rItem.Which() != ATTR_PATTERN ) // Only Pattern is special
        return SfxItemPool::PutImpl( rItem, nWhich, bPassingOwnership );

    // Don't copy the default pattern of this Pool
    if (&rItem == mvPoolDefaults[ ATTR_PATTERN - ATTR_STARTINDEX ])
        return rItem;

    // Else Put must always happen, because it could be another Pool
    const SfxPoolItem& rNew = SfxItemPool::PutImpl( rItem, nWhich, bPassingOwnership );
    sal_uInt32 nRef = rNew.GetRefCount();
    if (nRef == 1)
    if (ATTR_PATTERN == rItem.Which() && 1 == rItem.GetRefCount())
    {
        ++mnCurrentMaxKey;
        const_cast<ScPatternAttr&>(static_cast<const ScPatternAttr&>(rNew)).SetKey(mnCurrentMaxKey);
        const_cast<ScDocumentPool*>(this)->mnCurrentMaxKey++;
        const_cast<ScPatternAttr&>(static_cast<const ScPatternAttr&>(rItem)).SetPAKey(mnCurrentMaxKey);
    }
    return rNew;
}

bool ScDocumentPool::newItem_UseDirect(const SfxPoolItem& rItem) const
{
    // I have evaluated that this is currently needed for ATTR_PATTERN/ScPatternAttr to work,
    // so this needs to stay at ptr-compare
    return (ATTR_PATTERN == rItem.Which() && areSfxPoolItemPtrsEqual(&rItem, mvPoolDefaults[ATTR_PATTERN - ATTR_STARTINDEX]));
}

void ScDocumentPool::StyleDeleted( const ScStyleSheet* pStyle )
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index 8996577..6225e92 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -5060,7 +5060,7 @@ std::unique_ptr<ScPatternAttr> ScDocument::CreateSelectionPattern( const ScMarkD
    {
        std::unique_ptr<ScPatternAttr> pPattern(new ScPatternAttr( std::move(*aState.pItemSet) ));
        if (aState.mbValidPatternId)
            pPattern->SetKey(aState.mnPatternId);
            pPattern->SetPAKey(aState.mnPatternId);

        return pPattern;
    }
diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index 9a8675f..4a573e1 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -186,7 +186,7 @@ public:

bool isRotateItemUsed(const ScDocumentPool *pPool)
{
    return pPool->GetItemCount2( ATTR_ROTATE_VALUE ) > 0;
    return pPool->GetItemSurrogates(ATTR_ROTATE_VALUE).size() > 0;
}

void initRowInfo(const ScDocument* pDoc, RowInfo* pRowInfo, const SCSIZE nMaxRow,
@@ -488,11 +488,11 @@ void ScDocument::FillInfo(
                        const SvxLineItem* pBLTRLine = &pPattern->GetItem( ATTR_BORDER_BLTR );

                        const SvxShadowItem* pShadowAttr = &pPattern->GetItem(ATTR_SHADOW);
                        if (pShadowAttr != pDefShadow)
                        if (!SfxPoolItem::areSame(pShadowAttr, pDefShadow))
                            bAnyShadow = true;

                        const ScMergeAttr* pMergeAttr = &pPattern->GetItem(ATTR_MERGE);
                        bool bMerged = ( pMergeAttr != pDefMerge && *pMergeAttr != *pDefMerge );
                        bool bMerged = !SfxPoolItem::areSame( pMergeAttr, pDefMerge );
                        ScMF nOverlap = pPattern->GetItemSet().
                                                        Get(ATTR_MERGE_FLAG).GetValue();
                        bool bHOverlapped(nOverlap & ScMF::Hor);
@@ -530,7 +530,7 @@ void ScDocument::FillInfo(
                                if ( GetPreviewCellStyle( nCol, nCurRow, nTab  ) != nullptr )
                                    bAnyPreview = true;
                                RowInfo* pThisRowInfo = &pRowInfo[nArrRow];
                                if (pBackground != pDefBackground)          // Column background == Default ?
                                if (!SfxPoolItem::areSame(pBackground, pDefBackground))          // Column background == Default ?
                                    pThisRowInfo->bEmptyBack = false;
                                if (bContainsCondFormat)
                                    pThisRowInfo->bEmptyBack = false;
@@ -687,7 +687,7 @@ void ScDocument::FillInfo(
                if( bAnyCondition && pInfo->mxColorScale)
                {
                    pRowInfo[nArrRow].bEmptyBack = false;
                    pInfo->pBackground = &pPool->Put(SvxBrushItem(*pInfo->mxColorScale, ATTR_BACKGROUND));
                    pInfo->pBackground = &pPool->DirectPutItemInPool(SvxBrushItem(*pInfo->mxColorScale, ATTR_BACKGROUND));
                }
            }
        }
@@ -735,7 +735,7 @@ void ScDocument::FillInfo(
                        !(pShadowItem = pStartCond->GetItemIfSet(ATTR_SHADOW)) )
                        pShadowItem = &pStartPattern->GetItem(ATTR_SHADOW);
                    pInfo->pShadowAttr = pShadowItem;
                    if (pInfo->pShadowAttr != pDefShadow)
                    if (!SfxPoolItem::areSame(pInfo->pShadowAttr, pDefShadow))
                        bAnyShadow = true;

                    const ScCondFormatIndexes& rCondFormatIndex
diff --git a/sc/source/core/data/global.cxx b/sc/source/core/data/global.cxx
index 027bc57..57c9759 100644
--- a/sc/source/core/data/global.cxx
+++ b/sc/source/core/data/global.cxx
@@ -139,7 +139,7 @@ bool ScGlobal::HasAttrChanged( const SfxItemSet&  rNewAttrs,
        // Both Items set
        // PoolItems, meaning comparing pointers is valid
        if ( SfxItemState::SET == eOldState )
            bInvalidate = (pNewItem != pOldItem);
            bInvalidate = !SfxPoolItem::areSame(pNewItem, pOldItem);
    }
    else
    {
diff --git a/sc/source/core/data/patattr.cxx b/sc/source/core/data/patattr.cxx
index 7638652..d7d460a 100644
--- a/sc/source/core/data/patattr.cxx
+++ b/sc/source/core/data/patattr.cxx
@@ -72,30 +72,34 @@ ScPatternAttr::ScPatternAttr( SfxItemSet&& pItemSet, const OUString& rStyleName 
    :   SfxSetItem  ( ATTR_PATTERN, std::move(pItemSet) ),
        pName       ( rStyleName ),
        pStyle      ( nullptr ),
        mnKey(0)
        mnPAKey(0)
{
    setNewItemCallback();
}

ScPatternAttr::ScPatternAttr( SfxItemSet&& pItemSet )
    :   SfxSetItem  ( ATTR_PATTERN, std::move(pItemSet) ),
        pStyle      ( nullptr ),
        mnKey(0)
        mnPAKey(0)
{
    setNewItemCallback();
}

ScPatternAttr::ScPatternAttr( SfxItemPool* pItemPool )
    :   SfxSetItem  ( ATTR_PATTERN, SfxItemSetFixed<ATTR_PATTERN_START, ATTR_PATTERN_END>( *pItemPool ) ),
        pStyle      ( nullptr ),
        mnKey(0)
        mnPAKey(0)
{
    setNewItemCallback();
}

ScPatternAttr::ScPatternAttr( const ScPatternAttr& rPatternAttr )
    :   SfxSetItem  ( rPatternAttr ),
        pName       ( rPatternAttr.pName ),
        pStyle      ( rPatternAttr.pStyle ),
        mnKey(rPatternAttr.mnKey)
        mnPAKey(rPatternAttr.mnPAKey)
{
    setNewItemCallback();
}

ScPatternAttr* ScPatternAttr::Clone( SfxItemPool *pPool ) const
@@ -166,25 +170,6 @@ bool ScPatternAttr::operator==( const SfxPoolItem& rCmp ) const
            StrCmp( GetStyleName(), rOther.GetStyleName() );
}

SfxPoolItem::lookup_iterator ScPatternAttr::Lookup(lookup_iterator begin, lookup_iterator end ) const
{
    if( !mxHashCode )
        CalcHashCode();
    for( auto it = begin; it != end; ++it)
    {
        const ScPatternAttr* other = static_cast<const ScPatternAttr*>(*it);
        if( !other->mxHashCode )
            other->CalcHashCode();
        if (*mxHashCode == *other->mxHashCode
            && EqualPatternSets( GetItemSet(), other->GetItemSet())
            && StrCmp( GetStyleName(), other->GetStyleName()))
        {
            return it;
        }
    }
    return end;
}

SvxCellOrientation ScPatternAttr::GetCellOrientation( const SfxItemSet& rItemSet, const SfxItemSet* pCondSet )
{
    SvxCellOrientation eOrient = SvxCellOrientation::Standard;
@@ -1027,7 +1012,7 @@ void ScPatternAttr::DeleteUnchanged( const ScPatternAttr* pOldAttrs )
            if ( eOldState == SfxItemState::SET )
            {
                //  item is set in OldAttrs (or its parent) -> compare pointers
                if ( pThisItem == pOldItem )
                if (SfxPoolItem::areSame( pThisItem, pOldItem ))
                {
                    rThisSet.ClearItem( nSubWhich );
                    mxHashCode.reset();
@@ -1194,7 +1179,7 @@ ScPatternAttr* ScPatternAttr::PutInPool( ScDocument* pDestDoc, ScDocument* pSrcD
        }
    }

    ScPatternAttr* pPatternAttr = const_cast<ScPatternAttr*>( &pDestDoc->GetPool()->Put(aDestPattern) );
    ScPatternAttr* pPatternAttr = const_cast<ScPatternAttr*>( &pDestDoc->GetPool()->DirectPutItemInPool(aDestPattern) );
    return pPatternAttr;
}

@@ -1289,7 +1274,7 @@ bool ScPatternAttr::IsVisibleEqual( const ScPatternAttr& rOther ) const
            if (state1 != state2
                && (state1 < SfxItemState::DEFAULT || state2 < SfxItemState::DEFAULT))
                return false;
            if (pItem1 != pItem2)
            if (!SfxPoolItem::areSame(pItem1, pItem2))
                return false;
        }
        nWhich1 = aIter1.NextWhich();
@@ -1494,14 +1479,14 @@ ScRotateDir ScPatternAttr::GetRotateDir( const SfxItemSet* pCondSet ) const
    return nRet;
}

void ScPatternAttr::SetKey(sal_uInt64 nKey)
void ScPatternAttr::SetPAKey(sal_uInt64 nKey)
{
    mnKey = nKey;
    mnPAKey = nKey;
}

sal_uInt64 ScPatternAttr::GetKey() const
sal_uInt64 ScPatternAttr::GetPAKey() const
{
    return mnKey;
    return mnPAKey;
}

void ScPatternAttr::CalcHashCode() const
diff --git a/sc/source/core/data/table2.cxx b/sc/source/core/data/table2.cxx
index 978bd00..d6c1eea 100644
--- a/sc/source/core/data/table2.cxx
+++ b/sc/source/core/data/table2.cxx
@@ -2905,7 +2905,7 @@ namespace
        std::vector<ScAttrEntry> aData(rOrigData);
        for (size_t nIdx = 0; nIdx < aData.size(); ++nIdx)
        {
            aData[nIdx].pPattern = &rDocument.GetPool()->Put(*aData[nIdx].pPattern);
            aData[nIdx].pPattern = &rDocument.GetPool()->DirectPutItemInPool(*aData[nIdx].pPattern);
        }
        return aData;
    }
diff --git a/sc/source/core/data/table3.cxx b/sc/source/core/data/table3.cxx
index f0a55b4..71cf80b 100644
--- a/sc/source/core/data/table3.cxx
+++ b/sc/source/core/data/table3.cxx
@@ -1192,13 +1192,13 @@ void ScTable::SortReorderByRow( ScSortInfoArray* pArray, SCCOL nCol1, SCCOL nCol
            for (const auto& rSpan : aSpans)
            {
                assert(rSpan.mpPattern); // should never be NULL.
                rDocument.GetPool()->Put(*rSpan.mpPattern);
                rDocument.GetPool()->DirectPutItemInPool(*rSpan.mpPattern);
            }

            for (const auto& rSpan : aSpans)
            {
                aCol[nThisCol].SetPatternArea(rSpan.mnRow1, rSpan.mnRow2, *rSpan.mpPattern);
                rDocument.GetPool()->Remove(*rSpan.mpPattern);
                rDocument.GetPool()->DirectRemoveItemFromPool(*rSpan.mpPattern);
            }
        }

@@ -1393,13 +1393,13 @@ void ScTable::SortReorderByRowRefUpdate(
            for (const auto& rSpan : aSpans)
            {
                assert(rSpan.mpPattern); // should never be NULL.
                rDocument.GetPool()->Put(*rSpan.mpPattern);
                rDocument.GetPool()->DirectPutItemInPool(*rSpan.mpPattern);
            }

            for (const auto& rSpan : aSpans)
            {
                aCol[nThisCol].SetPatternArea(rSpan.mnRow1, rSpan.mnRow2, *rSpan.mpPattern);
                rDocument.GetPool()->Remove(*rSpan.mpPattern);
                rDocument.GetPool()->DirectRemoveItemFromPool(*rSpan.mpPattern);
            }
        }

diff --git a/sc/source/core/data/table4.cxx b/sc/source/core/data/table4.cxx
index 9c68529..d8a4cf5 100644
--- a/sc/source/core/data/table4.cxx
+++ b/sc/source/core/data/table4.cxx
@@ -1005,7 +1005,7 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
                if ( bVertical && nISrcStart == nISrcEnd && !bHasFiltered )
                {
                    //  set all attributes at once (en bloc)
                    if (pNewPattern || pSrcPattern != rDocument.GetDefPattern())
                    if (pNewPattern || !SfxPoolItem::areSame(pSrcPattern, rDocument.GetDefPattern()))
                    {
                        //  Default is already present (DeleteArea)
                        SCROW nY1 = static_cast<SCROW>(std::min( nIStart, nIEnd ));
@@ -1036,7 +1036,7 @@ void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
                    DeleteArea(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow),
                            static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), InsertDeleteFlags::AUTOFILL);

                if ( pSrcPattern != aCol[nCol].GetPattern( static_cast<SCROW>(nRow) ) )
                if ( !SfxPoolItem::areSame(pSrcPattern, aCol[nCol].GetPattern( static_cast<SCROW>(nRow) ) ) )
                {
                    // Transfer template too
                    //TODO: Merge ApplyPattern to AttrArray ??
diff --git a/sc/source/filter/excel/xestyle.cxx b/sc/source/filter/excel/xestyle.cxx
index a68d640..2230987 100644
--- a/sc/source/filter/excel/xestyle.cxx
+++ b/sc/source/filter/excel/xestyle.cxx
@@ -2815,7 +2815,7 @@ sal_uInt32 XclExpXFBuffer::InsertCellXF( const ScPatternAttr* pPattern, sal_Int1
        pPattern = pDefPattern;

    // special handling for default cell formatting
    if( (pPattern == pDefPattern) && !bForceLineBreak &&
    if( SfxPoolItem::areSame(pPattern, pDefPattern) && !bForceLineBreak &&
        (nForceScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND) &&
        (nForceXclFont == EXC_FONT_NOTFOUND) )
    {
diff --git a/sc/source/filter/excel/xistyle.cxx b/sc/source/filter/excel/xistyle.cxx
index e1dc476..21b86a4 100644
--- a/sc/source/filter/excel/xistyle.cxx
+++ b/sc/source/filter/excel/xistyle.cxx
@@ -1405,7 +1405,7 @@ void XclImpXF::ApplyPatternToAttrVector(

    ScAttrEntry aEntry;
    aEntry.nEndRow = nRow2;
    aEntry.pPattern = &rDoc.GetPool()->Put(rPat);
    aEntry.pPattern = &rDoc.GetPool()->DirectPutItemInPool(rPat);
    rAttrs.push_back(aEntry);
}

diff --git a/sc/source/filter/lotus/lotattr.cxx b/sc/source/filter/lotus/lotattr.cxx
index f879840..458e3c6 100644
--- a/sc/source/filter/lotus/lotattr.cxx
+++ b/sc/source/filter/lotus/lotattr.cxx
@@ -189,7 +189,7 @@ void LotAttrCol::SetAttr( const ScDocument* pDoc, const SCROW nRow, const ScPatt

    if(iterLast != aEntries.rend())
    {
        if( ( (*iterLast)->nLastRow == nRow - 1 ) && ( &rAttr == (*iterLast)->pPattAttr ) )
        if( ( (*iterLast)->nLastRow == nRow - 1 ) && SfxPoolItem::areSame( &rAttr, (*iterLast)->pPattAttr ) )
            (*iterLast)->nLastRow = nRow;
        else
        {
diff --git a/sc/source/filter/oox/sheetdatabuffer.cxx b/sc/source/filter/oox/sheetdatabuffer.cxx
index d1410eb..b25dba6 100644
--- a/sc/source/filter/oox/sheetdatabuffer.cxx
+++ b/sc/source/filter/oox/sheetdatabuffer.cxx
@@ -523,7 +523,7 @@ void SheetDataBuffer::finalizeImport()
            ScAttrEntry aEntry;
            aEntry.nEndRow = rDoc.MaxRow();
            aEntry.pPattern = pDefPattern;
            rDoc.GetPool()->Put(*aEntry.pPattern);
            rDoc.GetPool()->DirectPutItemInPool(*aEntry.pPattern);
            aAttrs.maAttrs.push_back(aEntry);

            if (!sc::NumFmtUtil::isLatinScript(*aEntry.pPattern, rDoc))
diff --git a/sc/source/filter/oox/stylesbuffer.cxx b/sc/source/filter/oox/stylesbuffer.cxx
index e38b5cd..7481b1d 100644
--- a/sc/source/filter/oox/stylesbuffer.cxx
+++ b/sc/source/filter/oox/stylesbuffer.cxx
@@ -2168,7 +2168,7 @@ void Xf::applyPatternToAttrList( AttrList& rAttrs, SCROW nRow1, SCROW nRow2, sal
        // Fill this gap with the default pattern.
        ScAttrEntry aEntry;
        aEntry.nEndRow = nRow1 - 1;
        aEntry.pPattern = &rDoc.GetPool()->Put(*rAttrs.mpDefPattern);
        aEntry.pPattern = &rDoc.GetPool()->DirectPutItemInPool(*rAttrs.mpDefPattern);
        rAttrs.maAttrs.push_back(aEntry);

        // Check if the default pattern is 'General'.
@@ -2178,7 +2178,7 @@ void Xf::applyPatternToAttrList( AttrList& rAttrs, SCROW nRow1, SCROW nRow2, sal

    ScAttrEntry aEntry;
    aEntry.nEndRow = nRow2;
    aEntry.pPattern = &rDoc.GetPool()->Put(rPat);
    aEntry.pPattern = &rDoc.GetPool()->DirectPutItemInPool(rPat);
    // Put the allocated pattern to cache
    if (!pCachedPattern)
        rCache.add(nXfId, nNumFmtId, const_cast<ScPatternAttr*>(aEntry.pPattern));
diff --git a/sc/source/ui/app/inputhdl.cxx b/sc/source/ui/app/inputhdl.cxx
index de2ce36..769f424 100644
--- a/sc/source/ui/app/inputhdl.cxx
+++ b/sc/source/ui/app/inputhdl.cxx
@@ -2519,7 +2519,7 @@ bool ScInputHandler::StartTable( sal_Unicode cTyped, bool bFromCommand, bool bIn
            const ScPatternAttr* pPattern = rDoc.GetPattern( aCursorPos.Col(),
                                                              aCursorPos.Row(),
                                                              aCursorPos.Tab() );
            if (pPattern != pLastPattern)
            if (!SfxPoolItem::areSame(pPattern, pLastPattern))
            {
                // Percent format?
                const SfxItemSet& rAttrSet = pPattern->GetItemSet();
diff --git a/sc/source/ui/app/msgpool.cxx b/sc/source/ui/app/msgpool.cxx
index 58daba68..227dbce 100644
--- a/sc/source/ui/app/msgpool.cxx
+++ b/sc/source/ui/app/msgpool.cxx
@@ -25,16 +25,17 @@

SfxItemInfo const aMsgItemInfos[] =
{
    { 0,                         true },   // SCITEM_STRING
    { 0,                         true },   // SCITEM_SEARCHDATA - stop using this!
    { SID_SORT,                  true },   // SCITEM_SORTDATA
    { SID_QUERY,                 true },   // SCITEM_QUERYDATA
    { SID_SUBTOTALS,             true },   // SCITEM_SUBTDATA
    { SID_CONSOLIDATE,           true },   // SCITEM_CONSOLIDATEDATA
    { SID_PIVOT_TABLE,           true },   // SCITEM_PIVOTDATA
    { SID_SOLVE,                 true },   // SCITEM_SOLVEDATA
    { SID_SCUSERLISTS,           true },   // SCITEM_USERLIST
    { 0,                         false }  // SCITEM_CONDFORMATDLGDATA
    // _nSID, _bNeedsPoolRegistration, _bShareable
    { 0,                         false, true },   // SCITEM_STRING
    { 0,                         false, true },   // SCITEM_SEARCHDATA - stop using this!
    { SID_SORT,                  false, true },   // SCITEM_SORTDATA
    { SID_QUERY,                 false, true },   // SCITEM_QUERYDATA
    { SID_SUBTOTALS,             false, true },   // SCITEM_SUBTDATA
    { SID_CONSOLIDATE,           false, true },   // SCITEM_CONSOLIDATEDATA
    { SID_PIVOT_TABLE,           false, true },   // SCITEM_PIVOTDATA
    { SID_SOLVE,                 false, true },   // SCITEM_SOLVEDATA
    { SID_SCUSERLISTS,           false, true },   // SCITEM_USERLIST
    { 0,                         true,  false }  // SCITEM_CONDFORMATDLGDATA
};

ScMessagePool::ScMessagePool()
diff --git a/sc/source/ui/condformat/condformatdlg.cxx b/sc/source/ui/condformat/condformatdlg.cxx
index 6fd71f9..2a1b724 100644
--- a/sc/source/ui/condformat/condformatdlg.cxx
+++ b/sc/source/ui/condformat/condformatdlg.cxx
@@ -634,7 +634,7 @@ void ScCondFormatDlg::OkPressed()
            pFormat->SetKey(nKey);
            pList->InsertNew(std::move(pFormat));
        }
        mpViewData->GetViewShell()->GetPool().Put(*mpDlgItem);
        mpViewData->GetViewShell()->GetPool().DirectPutItemInPool(*mpDlgItem);

        SetDispatcherLock( false );
        // Queue message to open Conditional Format Manager Dialog
@@ -650,7 +650,7 @@ void ScCondFormatDlg::CancelPressed()
{
    if ( mpDlgItem->IsManaged() )
    {
        mpViewData->GetViewShell()->GetPool().Put(*mpDlgItem);
        mpViewData->GetViewShell()->GetPool().DirectPutItemInPool(*mpDlgItem);
        SetDispatcherLock( false );
        // Queue message to open Conditional Format Manager Dialog
        GetBindings().GetDispatcher()->Execute( SID_OPENDLG_CONDFRMT_MANAGER,
diff --git a/sc/source/ui/inc/editsh.hxx b/sc/source/ui/inc/editsh.hxx
index 01457c3..3777d19 100644
--- a/sc/source/ui/inc/editsh.hxx
+++ b/sc/source/ui/inc/editsh.hxx
@@ -29,7 +29,7 @@ class SfxModule;
class EditView;
class ScViewData;
class ScInputHandler;
class SvxURLField;
class SvxFieldData;
class TransferableDataHelper;
class TransferableClipboardListener;

@@ -48,8 +48,14 @@ private:
    // currently happens to be when the menu was dismissed.
    std::optional<bool> moAtContextMenu_DisableEditHyperlink;

    const SvxURLField* GetURLField();
    const SvxURLField* GetFirstURLFieldFromCell();
    // These methods did return 'const SvxURLField*' before, but
    // at least for GetFirstURLFieldFromCell this is 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
    std::unique_ptr<const SvxFieldData> GetURLField();
    std::unique_ptr<const SvxFieldData> GetFirstURLFieldFromCell();

    ScInputHandler* GetMyInputHdl();

    DECL_LINK( ClipboardChanged, TransferableDataHelper*, void );
diff --git a/sc/source/ui/undo/undoblk3.cxx b/sc/source/ui/undo/undoblk3.cxx
index f614e0f..b7b615d 100644
--- a/sc/source/ui/undo/undoblk3.cxx
+++ b/sc/source/ui/undo/undoblk3.cxx
@@ -355,20 +355,20 @@ ScUndoSelectionAttr::ScUndoSelectionAttr( ScDocShell* pNewDocShell,
        bMulti      ( bNewMulti )
{
    ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
    pApplyPattern = const_cast<ScPatternAttr*>(&pPool->Put( *pNewApply ));
    pLineOuter = pNewOuter ? const_cast<SvxBoxItem*>( &pPool->Put( *pNewOuter ) ) : nullptr;
    pLineInner = pNewInner ? const_cast<SvxBoxInfoItem*>( &pPool->Put( *pNewInner ) ) : nullptr;
    pApplyPattern = const_cast<ScPatternAttr*>(&pPool->DirectPutItemInPool( *pNewApply ));
    pLineOuter = pNewOuter ? const_cast<SvxBoxItem*>( &pPool->DirectPutItemInPool( *pNewOuter ) ) : nullptr;
    pLineInner = pNewInner ? const_cast<SvxBoxInfoItem*>( &pPool->DirectPutItemInPool( *pNewInner ) ) : nullptr;
    aRangeCover = pRangeCover ? *pRangeCover : aRange;
}

ScUndoSelectionAttr::~ScUndoSelectionAttr()
{
    ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
    pPool->Remove(*pApplyPattern);
    pPool->DirectRemoveItemFromPool(*pApplyPattern);
    if (pLineOuter)
        pPool->Remove(*pLineOuter);
        pPool->DirectRemoveItemFromPool(*pLineOuter);
    if (pLineInner)
        pPool->Remove(*pLineInner);
        pPool->DirectRemoveItemFromPool(*pLineInner);

    pUndoDoc.reset();
}
diff --git a/sc/source/ui/undo/undocell.cxx b/sc/source/ui/undo/undocell.cxx
index 4cb9d03..84e4a95 100644
--- a/sc/source/ui/undo/undocell.cxx
+++ b/sc/source/ui/undo/undocell.cxx
@@ -84,17 +84,17 @@ ScUndoCursorAttr::ScUndoCursorAttr( ScDocShell* pNewDocShell,
    pNewEditData( static_cast<EditTextObject*>(nullptr) )
{
    ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
    pNewPattern = const_cast<ScPatternAttr*>( &pPool->Put( *pNewPat ) );
    pOldPattern = const_cast<ScPatternAttr*>( &pPool->Put( *pOldPat ) );
    pApplyPattern = const_cast<ScPatternAttr*>( &pPool->Put( *pApplyPat ) );
    pNewPattern = const_cast<ScPatternAttr*>( &pPool->DirectPutItemInPool( *pNewPat ) );
    pOldPattern = const_cast<ScPatternAttr*>( &pPool->DirectPutItemInPool( *pOldPat ) );
    pApplyPattern = const_cast<ScPatternAttr*>( &pPool->DirectPutItemInPool( *pApplyPat ) );
}

ScUndoCursorAttr::~ScUndoCursorAttr()
{
    ScDocumentPool* pPool = pDocShell->GetDocument().GetPool();
    pPool->Remove(*pNewPattern);
    pPool->Remove(*pOldPattern);
    pPool->Remove(*pApplyPattern);
    pPool->DirectRemoveItemFromPool(*pNewPattern);
    pPool->DirectRemoveItemFromPool(*pOldPattern);
    pPool->DirectRemoveItemFromPool(*pApplyPattern);
}

OUString ScUndoCursorAttr::GetComment() const
diff --git a/sc/source/ui/unoobj/cellsuno.cxx b/sc/source/ui/unoobj/cellsuno.cxx
index 59d77e35..3325b0b 100644
--- a/sc/source/ui/unoobj/cellsuno.cxx
+++ b/sc/source/ui/unoobj/cellsuno.cxx
@@ -2448,7 +2448,7 @@ void ScCellRangesBase::GetOnePropertyValue( const SfxItemPropertyMapEntry* pEntr
            case SC_WID_UNO_FORMATID:
                {
                    const ScPatternAttr* pPattern = GetCurrentAttrsFlat();
                    rAny <<= pPattern->GetKey();
                    rAny <<= pPattern->GetPAKey();
                }
            break;
        }
diff --git a/sc/source/ui/view/cellsh1.cxx b/sc/source/ui/view/cellsh1.cxx
index 1b30796..558d5a8 100644
--- a/sc/source/ui/view/cellsh1.cxx
+++ b/sc/source/ui/view/cellsh1.cxx
@@ -2410,7 +2410,7 @@ void ScCellShell::ExecuteEdit( SfxRequest& rReq )
                    // Conditional Format Dialog.
                    ScCondFormatDlgItem aDlgItem(nullptr, nIndex, false);
                    aDlgItem.SetDialogType(eType);
                    pTabViewShell->GetPool().Put(aDlgItem);
                    pTabViewShell->GetPool().DirectPutItemInPool(aDlgItem);

                    sal_uInt16      nId      = ScCondFormatDlgWrapper::GetChildWindowId();
                    SfxViewFrame& rViewFrm = pTabViewShell->GetViewFrame();
@@ -2878,7 +2878,7 @@ void ScCellShell::ExecuteEdit( SfxRequest& rReq )
                    {
                        // Put the xml string parameter to initialize the
                        // Conditional Format Dialog. ( add new )
                        pTabViewShell->GetPool().Put(ScCondFormatDlgItem(
                        pTabViewShell->GetPool().DirectPutItemInPool(ScCondFormatDlgItem(
                                    std::shared_ptr<ScConditionalFormatList>(pCondFormatList.release()), -1, true));
                        // Queue message to open Conditional Format Dialog
                        GetViewData().GetDispatcher().Execute( SID_OPENDLG_CONDFRMT, SfxCallMode::ASYNCHRON );
@@ -2889,7 +2889,7 @@ void ScCellShell::ExecuteEdit( SfxRequest& rReq )
                        sal_Int32 nIndex = pFormat ? pFormat->GetKey() : -1;
                        // Put the xml string parameter to initialize the
                        // Conditional Format Dialog. ( edit selected conditional format )
                        pTabViewShell->GetPool().Put(ScCondFormatDlgItem(
                        pTabViewShell->GetPool().DirectPutItemInPool(ScCondFormatDlgItem(
                                    std::shared_ptr<ScConditionalFormatList>(pCondFormatList.release()), nIndex, true));

                        // Queue message to open Conditional Format Dialog
@@ -2899,7 +2899,7 @@ void ScCellShell::ExecuteEdit( SfxRequest& rReq )
                        pCondFormatList.reset();

                    if (pDlgItem)
                        pTabViewShell->GetPool().Remove(*pDlgItem);
                        pTabViewShell->GetPool().DirectRemoveItemFromPool(*pDlgItem);

                    pDlg->disposeOnce();
                });
diff --git a/sc/source/ui/view/editsh.cxx b/sc/source/ui/view/editsh.cxx
index 493ab18..2c4328d 100644
--- a/sc/source/ui/view/editsh.cxx
+++ b/sc/source/ui/view/editsh.cxx
@@ -577,7 +577,8 @@ void ScEditShell::Execute( SfxRequest& rReq )
                    bool bDone = false;
                    if ( (eMode == HLINK_DEFAULT || eMode == HLINK_FIELD) && !bCellLinksOnly )
                    {
                        const SvxURLField* pURLField = GetURLField();
                        std::unique_ptr<const SvxFieldData> aSvxFieldDataPtr(GetURLField());
                        const SvxURLField* pURLField(static_cast<const SvxURLField*>(aSvxFieldDataPtr.get()));
                        if ( pURLField )
                        {
                            // select old field
@@ -637,7 +638,8 @@ void ScEditShell::Execute( SfxRequest& rReq )
            break;
        case SID_OPEN_HYPERLINK:
            {
                const SvxURLField* pURLField = GetURLField();
                std::unique_ptr<const SvxFieldData> aSvxFieldDataPtr(GetURLField());
                const SvxURLField* pURLField(static_cast<const SvxURLField*>(aSvxFieldDataPtr.get()));
                if ( pURLField )
                    ScGlobal::OpenURL( pURLField->GetURL(), pURLField->GetTargetFrame(), true );
                return;
@@ -792,7 +794,8 @@ void ScEditShell::GetState( SfxItemSet& rSet )
                    bool bCellLinksOnly
                        = SC_MOD()->GetAppOptions().GetLinksInsertedLikeMSExcel()
                          && rViewData.GetSfxDocShell()->GetMedium()->GetFilter()->IsMSOFormat();
                    const SvxURLField* pURLField = GetURLField();
                    std::unique_ptr<const SvxFieldData> aSvxFieldDataPtr(GetURLField());
                    const SvxURLField* pURLField(static_cast<const SvxURLField*>(aSvxFieldDataPtr.get()));
                    if (!bCellLinksOnly)
                    {
                        if (pURLField)
@@ -814,7 +817,8 @@ void ScEditShell::GetState( SfxItemSet& rSet )
                    {
                        if (!pURLField)
                        {
                            pURLField = GetFirstURLFieldFromCell();
                            aSvxFieldDataPtr = GetFirstURLFieldFromCell();
                            pURLField = static_cast<const SvxURLField*>(aSvxFieldDataPtr.get());
                        }
                        if (pURLField)
                        {
@@ -893,21 +897,21 @@ void ScEditShell::GetState( SfxItemSet& rSet )
    }
}

const SvxURLField* ScEditShell::GetURLField()
std::unique_ptr<const SvxFieldData> ScEditShell::GetURLField()
{
    ScInputHandler* pHdl = GetMyInputHdl();
    EditView* pActiveView = pHdl ? pHdl->GetActiveView() : pEditView;
    if (!pActiveView)
        return nullptr;
        return std::unique_ptr<const SvxFieldData>();

    const SvxFieldData* pField = pActiveView->GetFieldAtCursor();
    if (auto pURLField = dynamic_cast<const SvxURLField*>(pField))
        return pURLField;
        return pURLField->Clone();

    return nullptr;
    return std::unique_ptr<const SvxFieldData>();
}

const SvxURLField* ScEditShell::GetFirstURLFieldFromCell()
std::unique_ptr<const SvxFieldData> ScEditShell::GetFirstURLFieldFromCell()
{
    EditEngine* pEE = GetEditView()->GetEditEngine();
    sal_Int32 nParaCount = pEE->GetParagraphCount();
@@ -929,14 +933,15 @@ const SvxURLField* ScEditShell::GetFirstURLFieldFromCell()
                    const SvxFieldData* pField = pItem->GetField();
                    if (const SvxURLField* pUrlField = dynamic_cast<const SvxURLField*>(pField))
                    {
                        return pUrlField;
                        return pUrlField->Clone();
                    }
                }
            }
            aSel.nStartPos = aSel.nEndPos;
        }
    }
    return nullptr;

    return std::unique_ptr<const SvxFieldData>();
}

IMPL_LINK( ScEditShell, ClipboardChanged, TransferableDataHelper*, pDataHelper, void )
diff --git a/sc/source/ui/view/output.cxx b/sc/source/ui/view/output.cxx
index 8461aaa..47fdab3 100644
--- a/sc/source/ui/view/output.cxx
+++ b/sc/source/ui/view/output.cxx
@@ -766,14 +766,14 @@ static bool lcl_EqualBack( const RowInfo& rFirst, const RowInfo& rOther,
            const ScPatternAttr* pPat1 = rFirst.cellInfo(nX).pPatternAttr;
            const ScPatternAttr* pPat2 = rOther.cellInfo(nX).pPatternAttr;
            if ( !pPat1 || !pPat2 ||
                    &pPat1->GetItem(ATTR_PROTECTION) != &pPat2->GetItem(ATTR_PROTECTION) )
                    !SfxPoolItem::areSame(&pPat1->GetItem(ATTR_PROTECTION), &pPat2->GetItem(ATTR_PROTECTION) ) )
                return false;
        }
    }
    else
    {
        for ( nX=nX1; nX<=nX2; nX++ )
            if ( rFirst.cellInfo(nX).pBackground != rOther.cellInfo(nX).pBackground )
            if ( !SfxPoolItem::areSame(rFirst.cellInfo(nX).pBackground, rOther.cellInfo(nX).pBackground ) )
                return false;
    }

@@ -970,7 +970,7 @@ void drawCells(vcl::RenderContext& rRenderContext, std::optional<Color> const & 
        rRect.SetLeft( nPosX - nSignedOneX );
    }

    if ( pOldBackground && (pColor ||pBackground != pOldBackground || pOldDataBarInfo || pDataBarInfo || pIconSetInfo || pOldIconSetInfo) )
    if ( pOldBackground && (pColor || !SfxPoolItem::areSame(pBackground, pOldBackground) || pOldDataBarInfo || pDataBarInfo || pIconSetInfo || pOldIconSetInfo) )
    {
        rRect.SetRight( nPosX-nSignedOneX );
        if (pOldBackground)             // ==0 if hidden
diff --git a/sc/source/ui/view/output2.cxx b/sc/source/ui/view/output2.cxx
index 1b67ab4..2d6cda3 100644
--- a/sc/source/ui/view/output2.cxx
+++ b/sc/source/ui/view/output2.cxx
@@ -1025,71 +1025,71 @@ static bool StringDiffer( const ScPatternAttr*& rpOldPattern, const ScPatternAtt
{
    OSL_ENSURE( pNewPattern, "pNewPattern" );

    if ( pNewPattern == rpOldPattern )
    if ( SfxPoolItem::areSame( pNewPattern, rpOldPattern ) )
        return false;
    else if ( !rpOldPattern )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_FONT ) != &rpOldPattern->GetItem( ATTR_FONT ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_FONT ), &rpOldPattern->GetItem( ATTR_FONT ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_CJK_FONT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_CJK_FONT ), &rpOldPattern->GetItem( ATTR_CJK_FONT ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_CTL_FONT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_CTL_FONT ), &rpOldPattern->GetItem( ATTR_CTL_FONT ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_HEIGHT ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_FONT_HEIGHT ), &rpOldPattern->GetItem( ATTR_FONT_HEIGHT ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_CJK_FONT_HEIGHT ), &rpOldPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_CTL_FONT_HEIGHT ), &rpOldPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_WEIGHT ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_FONT_WEIGHT ), &rpOldPattern->GetItem( ATTR_FONT_WEIGHT ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_CJK_FONT_WEIGHT ), &rpOldPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_CTL_FONT_WEIGHT ), &rpOldPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_FONT_POSTURE ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_FONT_POSTURE ), &rpOldPattern->GetItem( ATTR_FONT_POSTURE ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_CJK_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_POSTURE ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_CJK_FONT_POSTURE ), &rpOldPattern->GetItem( ATTR_CJK_FONT_POSTURE ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_CTL_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_POSTURE ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_CTL_FONT_POSTURE ), &rpOldPattern->GetItem( ATTR_CTL_FONT_POSTURE ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_FONT_UNDERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_UNDERLINE ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_FONT_UNDERLINE ), &rpOldPattern->GetItem( ATTR_FONT_UNDERLINE ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_FONT_OVERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_OVERLINE ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_FONT_OVERLINE ), &rpOldPattern->GetItem( ATTR_FONT_OVERLINE ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_FONT_WORDLINE ) != &rpOldPattern->GetItem( ATTR_FONT_WORDLINE ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_FONT_WORDLINE ), &rpOldPattern->GetItem( ATTR_FONT_WORDLINE ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_FONT_CROSSEDOUT ) != &rpOldPattern->GetItem( ATTR_FONT_CROSSEDOUT ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_FONT_CROSSEDOUT ), &rpOldPattern->GetItem( ATTR_FONT_CROSSEDOUT ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_FONT_CONTOUR ) != &rpOldPattern->GetItem( ATTR_FONT_CONTOUR ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_FONT_CONTOUR ), &rpOldPattern->GetItem( ATTR_FONT_CONTOUR ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_FONT_SHADOWED ) != &rpOldPattern->GetItem( ATTR_FONT_SHADOWED ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_FONT_SHADOWED ), &rpOldPattern->GetItem( ATTR_FONT_SHADOWED ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_FONT_COLOR ) != &rpOldPattern->GetItem( ATTR_FONT_COLOR ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_FONT_COLOR ), &rpOldPattern->GetItem( ATTR_FONT_COLOR ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_HOR_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_HOR_JUSTIFY ), &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_HOR_JUSTIFY_METHOD ) != &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY_METHOD ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_HOR_JUSTIFY_METHOD ), &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY_METHOD ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_VER_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_VER_JUSTIFY ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_VER_JUSTIFY ), &rpOldPattern->GetItem( ATTR_VER_JUSTIFY ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_VER_JUSTIFY_METHOD ) != &rpOldPattern->GetItem( ATTR_VER_JUSTIFY_METHOD ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_VER_JUSTIFY_METHOD ), &rpOldPattern->GetItem( ATTR_VER_JUSTIFY_METHOD ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_STACKED ) != &rpOldPattern->GetItem( ATTR_STACKED ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_STACKED ), &rpOldPattern->GetItem( ATTR_STACKED ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_LINEBREAK ) != &rpOldPattern->GetItem( ATTR_LINEBREAK ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_LINEBREAK ), &rpOldPattern->GetItem( ATTR_LINEBREAK ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_MARGIN ) != &rpOldPattern->GetItem( ATTR_MARGIN ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_MARGIN ), &rpOldPattern->GetItem( ATTR_MARGIN ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_ROTATE_VALUE ) != &rpOldPattern->GetItem( ATTR_ROTATE_VALUE ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_ROTATE_VALUE ), &rpOldPattern->GetItem( ATTR_ROTATE_VALUE ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_FORBIDDEN_RULES ) != &rpOldPattern->GetItem( ATTR_FORBIDDEN_RULES ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_FORBIDDEN_RULES ), &rpOldPattern->GetItem( ATTR_FORBIDDEN_RULES ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_FONT_EMPHASISMARK ) != &rpOldPattern->GetItem( ATTR_FONT_EMPHASISMARK ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_FONT_EMPHASISMARK ), &rpOldPattern->GetItem( ATTR_FONT_EMPHASISMARK ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_FONT_RELIEF ) != &rpOldPattern->GetItem( ATTR_FONT_RELIEF ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_FONT_RELIEF ), &rpOldPattern->GetItem( ATTR_FONT_RELIEF ) ) )
        return true;
    else if ( &pNewPattern->GetItem( ATTR_BACKGROUND ) != &rpOldPattern->GetItem( ATTR_BACKGROUND ) )
    else if ( !SfxPoolItem::areSame( &pNewPattern->GetItem( ATTR_BACKGROUND ), &rpOldPattern->GetItem( ATTR_BACKGROUND ) ) )
        return true;    // needed with automatic text color
    else
    {
@@ -1714,7 +1714,7 @@ void ScOutputData::LayoutStrings(bool bPixelToLogic)
                    if (nScript == SvtScriptType::NONE)
                        nScript = ScGlobal::GetDefaultScriptType();

                    if ( pPattern != pOldPattern || pCondSet != pOldCondSet ||
                    if ( !SfxPoolItem::areSame(pPattern, pOldPattern) || pCondSet != pOldCondSet ||
                         nScript != nOldScript || mbSyntaxMode )
                    {
                        if ( StringDiffer(pOldPattern,pPattern) ||
@@ -2488,7 +2488,7 @@ void ScOutputData::DrawEditParam::setPatternToEngine(bool bUseStyleColor)
    // syntax highlighting mode is ignored here
    // StringDiffer doesn't look at hyphenate, language items

    if (mpPattern == mpOldPattern && mpCondSet == mpOldCondSet && mpPreviewFontSet == mpOldPreviewFontSet )
    if (SfxPoolItem::areSame(mpPattern, mpOldPattern) && mpCondSet == mpOldCondSet && mpPreviewFontSet == mpOldPreviewFontSet )
        return;

    Color nConfBackColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
@@ -4701,7 +4701,7 @@ void ScOutputData::DrawRotated(bool bPixelToLogic)
                            // syntax mode is ignored here...

                            // StringDiffer doesn't look at hyphenate, language items
                            if ( pPattern != pOldPattern || pCondSet != pOldCondSet )
                            if ( !SfxPoolItem::areSame(pPattern, pOldPattern) || pCondSet != pOldCondSet )
                            {
                                auto pSet = std::make_unique<SfxItemSet>( mxOutputEditEngine->GetEmptyItemSet() );
                                pPattern->FillEditItemSet( pSet.get(), pCondSet );
diff --git a/sc/source/ui/view/spelleng.cxx b/sc/source/ui/view/spelleng.cxx
index f325d7d..ae50d82 100644
--- a/sc/source/ui/view/spelleng.cxx
+++ b/sc/source/ui/view/spelleng.cxx
@@ -209,7 +209,7 @@ bool ScConversionEngineBase::FindNextConversionCell()
            {
                // GetPattern may implicitly allocates the column if not exists,
                pPattern = mrDoc.GetPattern( nNewCol, nNewRow, mnStartTab );
                if( pPattern && (pPattern != pLastPattern) )
                if( pPattern && !SfxPoolItem::areSame(pPattern, pLastPattern) )
                {
                    pPattern->FillEditItemSet( &aEditDefaults );
                    SetDefaults( aEditDefaults );
diff --git a/sc/source/ui/view/tabvwshc.cxx b/sc/source/ui/view/tabvwshc.cxx
index 47a15f6..d253e81 100644
--- a/sc/source/ui/view/tabvwshc.cxx
+++ b/sc/source/ui/view/tabvwshc.cxx
@@ -440,7 +440,7 @@ std::shared_ptr<SfxModelessDialogController> ScTabViewShell::CreateRefDialogCont
                xResult = std::make_shared<ScCondFormatDlg>(pB, pCW, pParent, &rViewData, pDlgItem);

                // Remove the pool item stored by Conditional Format Manager Dialog.
                GetPool().Remove(*pDlgItem);
                GetPool().DirectRemoveItemFromPool(*pDlgItem);
            }

            break;
diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx
index af0dc57..cffb0dc 100644
--- a/sc/source/ui/view/viewfunc.cxx
+++ b/sc/source/ui/view/viewfunc.cxx
@@ -1050,8 +1050,8 @@ void ScViewFunc::ApplyAttributes( const SfxItemSet* pDialogSet,
    SfxItemSet&           rNewSet   = aNewAttrs.GetItemSet();
    SfxItemPool*          pNewPool  = rNewSet.GetPool();

    pNewPool->Put(rNewOuter);        // don't delete yet
    pNewPool->Put(rNewInner);
    pNewPool->DirectPutItemInPool(rNewOuter);        // don't delete yet
    pNewPool->DirectPutItemInPool(rNewInner);
    rNewSet.ClearItem( ATTR_BORDER );
    rNewSet.ClearItem( ATTR_BORDER_INNER );

@@ -1065,7 +1065,7 @@ void ScViewFunc::ApplyAttributes( const SfxItemSet* pDialogSet,
    bool bFrame =    (pDialogSet->GetItemState( ATTR_BORDER ) != SfxItemState::DEFAULT)
                  || (pDialogSet->GetItemState( ATTR_BORDER_INNER ) != SfxItemState::DEFAULT);

    if (&rNewOuter == &rOldOuter && &rNewInner == &rOldInner)
    if (SfxPoolItem::areSame(&rNewOuter, &rOldOuter) && SfxPoolItem::areSame(&rNewInner, &rOldInner))
        bFrame = false;

    //  this should be intercepted by the pool: ?!??!??
@@ -1095,8 +1095,8 @@ void ScViewFunc::ApplyAttributes( const SfxItemSet* pDialogSet,
                           bDefNewInner ? &rOldInner : &rNewInner );
    }

    pNewPool->Remove(rNewOuter);         // release
    pNewPool->Remove(rNewInner);
    pNewPool->DirectRemoveItemFromPool(rNewOuter);         // release
    pNewPool->DirectRemoveItemFromPool(rNewInner);

    //  adjust height only if needed
    if (bAdjustBlockHeight)
diff --git a/sd/source/ui/func/fupage.cxx b/sd/source/ui/func/fupage.cxx
index 4660c1d..9401a56 100644
--- a/sd/source/ui/func/fupage.cxx
+++ b/sd/source/ui/func/fupage.cxx
@@ -373,7 +373,7 @@ const SfxItemSet* FuPage::ExecuteDialog(weld::Window* pParent, const SfxRequest&
                    if( pTempSet->GetItemState( i ) == SfxItemState::DEFAULT )
                        pTempSet->Put( aMergedAttr.Get( i ) );
                    else
                        if( aMergedAttr.GetItem( i ) != pTempSet->GetItem( i ) )
                        if( !SfxPoolItem::areSame(aMergedAttr.GetItem( i ), pTempSet->GetItem( i ) ) )
                            bChanges = true;
                }
            }
diff --git a/sd/source/ui/unoidl/unomodel.cxx b/sd/source/ui/unoidl/unomodel.cxx
index 77aeb44..802aab2 100644
--- a/sd/source/ui/unoidl/unomodel.cxx
+++ b/sd/source/ui/unoidl/unomodel.cxx
@@ -1383,12 +1383,13 @@ uno::Any SAL_CALL SdXImpressDocument::getPropertyValue( const OUString& Property

                for(sal_uInt16 nWhichId : aWhichIds)
                {
                    sal_uInt32 nItems = rPool.GetItemCount2( nWhichId );
                    const registeredSfxPoolItems& rSurrogates(rPool.GetItemSurrogates(nWhichId));
                    const sal_uInt32 nItems(rSurrogates.size());

                    aSeq.realloc( aSeq.getLength() + nItems*5 + 5 );
                    auto pSeq = aSeq.getArray();

                    for (const SfxPoolItem* pItem : rPool.GetItemSurrogates(nWhichId))
                    for (const SfxPoolItem* pItem : rSurrogates)
                    {
                        const SvxFontItem *pFont = static_cast<const SvxFontItem *>(pItem);

diff --git a/sfx2/source/control/shell.cxx b/sfx2/source/control/shell.cxx
index 5cba99c..f4b2960 100644
--- a/sfx2/source/control/shell.cxx
+++ b/sfx2/source/control/shell.cxx
@@ -158,7 +158,7 @@ void SfxShell::PutItem
                                  which is stored in the SfxShell in a list. */
)
{
    DBG_ASSERT( dynamic_cast< const SfxSetItem* >( &rItem) ==  nullptr, "SetItems aren't allowed here" );
    DBG_ASSERT( !rItem.isSetItem(), "SetItems aren't allowed here" );
    DBG_ASSERT( SfxItemPool::IsSlot( rItem.Which() ),
                "items with Which-Ids aren't allowed here" );

diff --git a/sfx2/source/control/statcach.cxx b/sfx2/source/control/statcach.cxx
index cf059af..2346333 100644
--- a/sfx2/source/control/statcach.cxx
+++ b/sfx2/source/control/statcach.cxx
@@ -404,14 +404,7 @@ void SfxStateCache::SetState_Impl
    bool bNotify = bItemDirty;
    if ( !bItemDirty )
    {
        bool bBothAvailable = pLastItem && pState &&
                    !IsInvalidItem(pState) && !IsInvalidItem(pLastItem);
        DBG_ASSERT( !bBothAvailable || pState != pLastItem, "setting state with own item" );
        if ( bBothAvailable )
            bNotify = typeid(*pState) != typeid(*pLastItem) ||
                      *pState != *pLastItem;
        else
            bNotify = ( pState != pLastItem ) || ( eState != eLastState );
        bNotify = !SfxPoolItem::areSame(pLastItem, pState) || (eState != eLastState);
    }

    if ( bNotify )
diff --git a/sfx2/source/dialog/dinfdlg.cxx b/sfx2/source/dialog/dinfdlg.cxx
index c11419d..044757c6 100644
--- a/sfx2/source/dialog/dinfdlg.cxx
+++ b/sfx2/source/dialog/dinfdlg.cxx
@@ -731,7 +731,8 @@ bool SfxDocumentDescPage::FillItemSet(SfxItemSet *rSet)
        pInfo->setDescription( m_xCommentEd->get_text() );
    }
    rSet->Put( *pInfo );
    if ( pInfo != m_pInfoItem )
    // ptr compare OK, pInfo was created above as temporary data holder
    if ( !areSfxPoolItemPtrsEqual(pInfo, m_pInfoItem) )
    {
        delete pInfo;
    }
diff --git a/sfx2/source/explorer/nochaos.cxx b/sfx2/source/explorer/nochaos.cxx
index 1ec9f10..999db2d 100644
--- a/sfx2/source/explorer/nochaos.cxx
+++ b/sfx2/source/explorer/nochaos.cxx
@@ -165,7 +165,7 @@ inline void CntStaticPoolDefaults_Impl::Insert(

    mvDefaults[ nPos ]         = pItem;
    m_pItemInfos[ nPos ]._nSID   = 0;
    m_pItemInfos[ nPos ]._bPoolable = true;
    m_pItemInfos[ nPos ]._bNeedsPoolRegistration = false;
}


diff --git a/svl/qa/unit/items/stylepool.cxx b/svl/qa/unit/items/stylepool.cxx
index 94ff91a..d852dd2 100644
--- a/svl/qa/unit/items/stylepool.cxx
+++ b/svl/qa/unit/items/stylepool.cxx
@@ -26,7 +26,9 @@ CPPUNIT_TEST_FIXTURE(StylePoolTest, testIterationOrder)
    // Set up a style pool with multiple parents.
    SfxStringItem aDefault1(1);
    std::vector<SfxPoolItem*> aDefaults{ &aDefault1 };
    SfxItemInfo const aItems[] = { { 2, false } };
    SfxItemInfo const aItems[] = { // _nSID, _bNeedsPoolRegistration, _bShareable
                                   { 2, false, false }
    };

    rtl::Reference<SfxItemPool> pPool = new SfxItemPool("test", 1, 1, aItems);
    pPool->SetDefaults(&aDefaults);
diff --git a/svl/qa/unit/items/test_itempool.cxx b/svl/qa/unit/items/test_itempool.cxx
index 339da00..c8e313b 100644
--- a/svl/qa/unit/items/test_itempool.cxx
+++ b/svl/qa/unit/items/test_itempool.cxx
@@ -35,63 +35,71 @@ class PoolItemTest : public CppUnit::TestFixture
void PoolItemTest::testPool()
{
    SfxItemInfo const aItems[] =
        { { 4, true },
          { 3, false /* not poolable */ },
          { 2, false },
          { 1, false /* not poolable */}
        };
    {
        // _nSID, _bNeedsPoolRegistration, _bShareable
        { 4, false, true },
        { 3, true,  false /* test NeedsPoolRegistration */ },
        { 2, false, false },
        { 1, true,  false /* test NeedsPoolRegistration */}
    };

    rtl::Reference<SfxItemPool> pPool = new SfxItemPool("testpool", 1, 4, aItems);
    SfxItemPool_Impl *pImpl = SfxItemPool_Impl::GetImpl(pPool.get());
    CPPUNIT_ASSERT(pImpl != nullptr);
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(4), pImpl->maPoolItemArrays.size());

    // Poolable
    SfxVoidItem aItemOne( 1 );
    SfxVoidItem aNotherOne( 1 );

    {
        CPPUNIT_ASSERT(pImpl->maPoolItemArrays[0].empty());
        const SfxPoolItem &rVal = pPool->Put(aItemOne);
        CPPUNIT_ASSERT(nullptr == pPool->ppRegisteredSfxPoolItems);
        const SfxPoolItem &rVal = pPool->DirectPutItemInPool(aItemOne);
        CPPUNIT_ASSERT(bool(rVal == aItemOne));
        CPPUNIT_ASSERT(!pImpl->maPoolItemArrays[0].empty());
        const SfxPoolItem &rVal2 = pPool->Put(aNotherOne);
        CPPUNIT_ASSERT(nullptr != pPool->ppRegisteredSfxPoolItems);
        CPPUNIT_ASSERT(nullptr != pPool->ppRegisteredSfxPoolItems[0]);
        CPPUNIT_ASSERT(!pPool->ppRegisteredSfxPoolItems[0]->empty());
        const SfxPoolItem &rVal2 = pPool->DirectPutItemInPool(aNotherOne);
        CPPUNIT_ASSERT(bool(rVal2 == rVal));
        CPPUNIT_ASSERT_EQUAL(&rVal, &rVal2);

        // ITEM: With leaving the paradigm that internally an already
        //   existing Item with true = operator==() (which is very
        //   expensive) the ptr's are no longer required to be equal,
        //   but the content-compare *is*
        CPPUNIT_ASSERT(SfxPoolItem::areSame(rVal, rVal2));

        // Clones on Put ...
        CPPUNIT_ASSERT(&rVal2 != &aItemOne);
        CPPUNIT_ASSERT(&rVal2 != &aNotherOne);
        CPPUNIT_ASSERT(&rVal != &aItemOne);
        CPPUNIT_ASSERT(&rVal != &aNotherOne);
        // ptr compare OK, we want to check just the ptrs here
        CPPUNIT_ASSERT(!areSfxPoolItemPtrsEqual(&rVal2, &aItemOne));
        CPPUNIT_ASSERT(!areSfxPoolItemPtrsEqual(&rVal2, &aNotherOne));
        CPPUNIT_ASSERT(!areSfxPoolItemPtrsEqual(&rVal, &aItemOne));
        CPPUNIT_ASSERT(!areSfxPoolItemPtrsEqual(&rVal, &aNotherOne));
    }

    // non-poolable
    SfxVoidItem aItemTwo( 2 );
    SfxVoidItem aNotherTwo( 2 );
    {
        CPPUNIT_ASSERT(pImpl->maPoolItemArrays[1].empty());
        const SfxPoolItem &rVal = pPool->Put(aItemTwo);
        CPPUNIT_ASSERT(nullptr == pPool->ppRegisteredSfxPoolItems[1]);
        const SfxPoolItem &rVal = pPool->DirectPutItemInPool(aItemTwo);
        CPPUNIT_ASSERT(bool(rVal == aItemTwo));
        CPPUNIT_ASSERT(!pImpl->maPoolItemArrays[1].empty());

        const SfxPoolItem &rVal2 = pPool->Put(aNotherTwo);
        CPPUNIT_ASSERT(nullptr != pPool->ppRegisteredSfxPoolItems[1]);
        CPPUNIT_ASSERT(!pPool->ppRegisteredSfxPoolItems[1]->empty());
        const SfxPoolItem &rVal2 = pPool->DirectPutItemInPool(aNotherTwo);
        CPPUNIT_ASSERT(bool(rVal2 == rVal));
        CPPUNIT_ASSERT(&rVal2 != &rVal);
        // ptr compare OK, we want to check just the ptrs here
        CPPUNIT_ASSERT(!areSfxPoolItemPtrsEqual(&rVal2, &rVal));
    }

    // Test removal.
    SfxVoidItem aRemoveFour(4);
    SfxVoidItem aNotherFour(4);
    const SfxPoolItem &rKeyFour = pPool->Put(aRemoveFour);
    pPool->Put(aNotherFour);
    CPPUNIT_ASSERT(pImpl->maPoolItemArrays[3].size() > 0);
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), pImpl->maPoolItemArrays[3].size());
    pPool->Remove(rKeyFour);
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pImpl->maPoolItemArrays[3].size());
    pPool->Put(aNotherFour);
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), pImpl->maPoolItemArrays[3].size());

    const SfxPoolItem &rKeyFour = pPool->DirectPutItemInPool(aRemoveFour);
    pPool->DirectPutItemInPool(aNotherFour);
    CPPUNIT_ASSERT(pPool->ppRegisteredSfxPoolItems[3]->size() > 0);
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), pPool->ppRegisteredSfxPoolItems[3]->size());
    pPool->DirectRemoveItemFromPool(rKeyFour);
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), pPool->ppRegisteredSfxPoolItems[3]->size());
    pPool->DirectPutItemInPool(aNotherFour);
    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), pPool->ppRegisteredSfxPoolItems[3]->size());
}


diff --git a/svl/source/inc/poolio.hxx b/svl/source/inc/poolio.hxx
index cc406f3..118deaf 100644
--- a/svl/source/inc/poolio.hxx
+++ b/svl/source/inc/poolio.hxx
@@ -31,128 +31,9 @@
class SfxPoolItem;
class SfxItemPoolUser;

const sal_uInt32 SFX_ITEMS_DEFAULT = 0xfffffffe;

static bool CompareSortablePoolItems(SfxPoolItem const* lhs, SfxPoolItem const* rhs)
{
    return (*lhs) < (*rhs);
}
/**
 * This array contains a set of SfxPoolItems, if those items are
 * poolable then each item has a unique set of properties, and we
 * often search linearly to ensure uniqueness. If they are
 * non-poolable we maintain an (often large) list of pointers.
 */
struct SfxPoolItemArray_Impl
{
private:
    o3tl::sorted_vector<SfxPoolItem*> maPoolItemSet;
    // In some cases, e.g. subclasses of NameOrIndex, the parent class (NameOrIndex) is sortable,
    // but the subclasses do not define an operator<, which means that we don't get an ordering
    // strong enough to enforce uniqueness purely with operator<, which means we need to do
    // a partial scan with operator==
    std::vector<SfxPoolItem*> maSortablePoolItems;
public:
    o3tl::sorted_vector<SfxPoolItem*>::const_iterator begin() const { return maPoolItemSet.begin(); }
    o3tl::sorted_vector<SfxPoolItem*>::const_iterator end() const { return maPoolItemSet.end(); }
    /// clear array of PoolItem variants after all PoolItems are deleted
    /// or all ref counts are decreased
    void clear();
    size_t size() const {return maPoolItemSet.size();}
    bool empty() const {return maPoolItemSet.empty();}
    o3tl::sorted_vector<SfxPoolItem*>::const_iterator find(SfxPoolItem* pItem) const { return maPoolItemSet.find(pItem); }
    void insert(SfxPoolItem* pItem)
    {
        bool bInserted = maPoolItemSet.insert(pItem).second;
        assert( bInserted && "duplicate item?" );
        (void)bInserted;

        if (pItem->IsSortable())
        {
            // bail early if someone modified one of these things underneath me
            assert( std::is_sorted_until(maSortablePoolItems.begin(), maSortablePoolItems.end(), CompareSortablePoolItems) == maSortablePoolItems.end());

            auto it = std::lower_bound(maSortablePoolItems.begin(), maSortablePoolItems.end(), pItem, CompareSortablePoolItems);
            maSortablePoolItems.insert(maSortablePoolItems.begin() + (it - maSortablePoolItems.begin()), pItem);
        }
    }
    const SfxPoolItem* findByLessThan(const SfxPoolItem* pNeedle) const
    {
        // bail early if someone modified one of these things underneath me
        assert( std::is_sorted_until(maSortablePoolItems.begin(), maSortablePoolItems.end(), CompareSortablePoolItems) == maSortablePoolItems.end());
        assert( maPoolItemSet.empty() || maPoolItemSet.front()->IsSortable() );

        auto it = std::lower_bound(maSortablePoolItems.begin(), maSortablePoolItems.end(), pNeedle, CompareSortablePoolItems);
        for (;;)
        {
            if (it == maSortablePoolItems.end())
                return nullptr;
            if (*pNeedle < **it)
                return nullptr;
            if (*pNeedle == **it)
                return *it;
            ++it;
        }
    }
    std::vector<const SfxPoolItem*> findSurrogateRange(const SfxPoolItem* pNeedle) const
    {
        std::vector<const SfxPoolItem*> rv;
        if (!maSortablePoolItems.empty())
        {
            // bail early if someone modified one of these things underneath me
            assert( std::is_sorted_until(maSortablePoolItems.begin(), maSortablePoolItems.end(), CompareSortablePoolItems) == maSortablePoolItems.end());

            auto range = std::equal_range(maSortablePoolItems.begin(), maSortablePoolItems.end(), pNeedle, CompareSortablePoolItems);
            rv.reserve(std::distance(range.first, range.second));
            for (auto it = range.first; it != range.second; ++it)
                rv.push_back(*it);
        }
        else
        {
            for (const SfxPoolItem* p : maPoolItemSet)
                if (*pNeedle == *p)
                    rv.push_back(p);
        }
        return rv;
    }
    void erase(o3tl::sorted_vector<SfxPoolItem*>::const_iterator it)
    {
        auto pNeedle = *it;
        if ((*it)->IsSortable())
        {
            // bail early if someone modified one of these things underneath me
            assert( std::is_sorted_until(maSortablePoolItems.begin(), maSortablePoolItems.end(), CompareSortablePoolItems) == maSortablePoolItems.end());

            auto sortIt = std::lower_bound(maSortablePoolItems.begin(), maSortablePoolItems.end(), pNeedle, CompareSortablePoolItems);
            for (;;)
            {
                if (sortIt == maSortablePoolItems.end())
                {
                    assert(false && "did not find item?");
                    break;
                }
                if (*pNeedle < **sortIt)
                {
                    assert(false && "did not find item?");
                    break;
                }
                // need to compare by pointer here, since we might have duplicates
                if (*sortIt == pNeedle)
                {
                    maSortablePoolItems.erase(sortIt);
                    break;
                }
                ++sortIt;
            }
        }
        maPoolItemSet.erase(it);
    }
};

struct SfxItemPool_Impl
{
    SfxBroadcaster                  aBC;
    std::vector<SfxPoolItemArray_Impl> maPoolItemArrays;
    OUString                        aName;
    std::vector<SfxPoolItem*>       maPoolDefaults;
    std::vector<SfxPoolItem*>*      mpStaticDefaults;
@@ -164,8 +45,7 @@ struct SfxItemPool_Impl
    MapUnit                         eDefMetric;

    SfxItemPool_Impl( SfxItemPool* pMaster, OUString _aName, sal_uInt16 nStart, sal_uInt16 nEnd )
        : maPoolItemArrays(nEnd - nStart + 1)
        , aName(std::move(_aName))
        : aName(std::move(_aName))
        , maPoolDefaults(nEnd - nStart + 1)
        , mpStaticDefaults(nullptr)
        , mpMaster(pMaster)
@@ -183,31 +63,11 @@ struct SfxItemPool_Impl

    void DeleteItems()
    {
        maPoolItemArrays.clear();
        maPoolDefaults.clear();
        mpPoolRanges.reset();
    }

    // unit testing
    friend class PoolItemTest;
    static SfxItemPool_Impl *GetImpl(SfxItemPool const *pPool) { return pPool->pImpl.get(); }
};


#define SFX_ITEMPOOL_VER_MAJOR          sal_uInt8(2)
#define SFX_ITEMPOOL_VER_MINOR          sal_uInt8(0)

#define SFX_ITEMPOOL_TAG_STARTPOOL_4    sal_uInt16(0x1111)
#define SFX_ITEMPOOL_TAG_STARTPOOL_5    sal_uInt16(0xBBBB)
#define SFX_ITEMPOOL_TAG_TRICK4OLD      sal_uInt16(0xFFFF)

#define SFX_ITEMPOOL_REC                sal_uInt8(0x01)
#define SFX_ITEMPOOL_REC_HEADER         sal_uInt8(0x10)
#define SFX_ITEMPOOL_REC_VERSIONMAP     sal_uInt16(0x0020)
#define SFX_ITEMPOOL_REC_WHICHIDS       sal_uInt16(0x0030)
#define SFX_ITEMPOOL_REC_ITEMS          sal_uInt16(0x0040)
#define SFX_ITEMPOOL_REC_DEFAULTS       sal_uInt16(0x0050)

#endif // INCLUDED_SVL_SOURCE_INC_POOLIO_HXX

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svl/source/items/custritm.cxx b/svl/source/items/custritm.cxx
index 21c835e..0d68b6d 100644
--- a/svl/source/items/custritm.cxx
+++ b/svl/source/items/custritm.cxx
@@ -33,14 +33,6 @@ bool CntUnencodedStringItem::operator ==(const SfxPoolItem & rItem) const
                m_aValue;
}

bool CntUnencodedStringItem::operator<(const SfxPoolItem & rItem) const
{
    assert(dynamic_cast<const CntUnencodedStringItem*>( &rItem ));
    return m_aValue
            < static_cast< const CntUnencodedStringItem * >(&rItem)->
                m_aValue;
}

// virtual
bool CntUnencodedStringItem::GetPresentation(SfxItemPresentation, MapUnit,
                                        MapUnit, OUString & rText,
diff --git a/svl/source/items/itempool.cxx b/svl/source/items/itempool.cxx
index 525adf3..0d32754 100644
--- a/svl/source/items/itempool.cxx
+++ b/svl/source/items/itempool.cxx
@@ -34,6 +34,170 @@
#include <cassert>
#include <vector>

#ifdef DBG_UTIL
static size_t nAllDirectlyPooledSfxPoolItemCount(0);
static size_t nRemainingDirectlyPooledSfxPoolItemCount(0);
size_t getAllDirectlyPooledSfxPoolItemCount() { return nAllDirectlyPooledSfxPoolItemCount; }
size_t getRemainingDirectlyPooledSfxPoolItemCount() { return nRemainingDirectlyPooledSfxPoolItemCount; }
#endif
// NOTE: Only needed for one Item in SC, see note in itemset.cxx
static bool g_bItemClassicMode(getenv("ITEM_CLASSIC_MODE"));

// WhichIDs that need to set _bNeedsPoolRegistration in SfxItemInfo
// to true to allow a register of all items of that type/with that WhichID
// to be accessible using SfxItemPool::GetItemSurrogates. Created by
// grepping for 'GetItemSurrogates' usages & interpreting. Some
// are double, more may be necessary. There is a SAL_INFO("svl.items", ...)
// in SfxItemPool::GetItemSurrogates that will give hints on missing flags.
//
// due to SwTable::UpdateFields
// due to SwCursorShell::GotoNxtPrvTableFormula
// due to DocumentFieldsManager::UpdateTableFields
// due to SwTable::GatherFormulas
//  RES_BOXATR_FORMULA ok
// due to SwContentTree::EditEntry
// due to SwDoc::FindINetAttr
// due to SwUndoResetAttr::RedoImpl
// due to SwContentTree::EditEntry
// due to SwContentTree::BringEntryToAttention
//  RES_TXTATR_REFMARK ok
// due to ImpEditEngine::WriteRTF
// due to ScDocument::UpdateFontCharSet()
// due to ScXMLFontAutoStylePool_Impl
// due to SdXImpressDocument::getPropertyValue
// due to Writer::AddFontItems_
//  EE_CHAR_FONTINFO ok
// due to ImpEditEngine::WriteRTF
// due to ScXMLFontAutoStylePool_Impl
// due to SdXImpressDocument::getPropertyValue
// due to Writer::AddFontItems_
//  EE_CHAR_FONTINFO_CJK ok
// due to ImpEditEngine::WriteRTF
// due to ScXMLFontAutoStylePool_Impl
// due to SdXImpressDocument::getPropertyValue
// due to Writer::AddFontItems_
//  EE_CHAR_FONTINFO_CTL ok
// due to ImpEditEngine::WriteRTF
//  EE_CHAR_COLOR ok
// due to ScDocumentPool::StyleDeleted
//  ATTR_PATTERN ok
// due to ScDocument::UpdateFontCharSet()
// due to ScXMLFontAutoStylePool_Impl
//  ATTR_FONT ok
// due to OptimizeHasAttrib
//  ATTR_ROTATE_VALUE ok
// due to ScDocument::GetDocColors()
//  ATTR_BACKGROUND ok
//  ATTR_FONT_COLOR ok
// due to ScXMLExport::CollectUserDefinedNamespaces
//  ATTR_USERDEF ok
// due to ScXMLExport::CollectUserDefinedNamespaces
// due to SwXMLExport::exportDoc
//  EE_PARA_XMLATTRIBS ok
// due to ScXMLExport::CollectUserDefinedNamespaces
// due to SwXMLExport::exportDoc
//  EE_CHAR_XMLATTRIBS ok
// due to ScXMLExport::CollectUserDefinedNamespaces
// due to SwXMLExport::exportDoc
//  SDRATTR_XMLATTRIBUTES ok
// due to ScXMLFontAutoStylePool_Impl
//  ATTR_CJK_FONT ok
//  ATTR_CTL_FONT ok
//  ATTR_PAGE_HEADERLEFT ok
//  ATTR_PAGE_FOOTERLEFT ok
//  ATTR_PAGE_HEADERRIGHT ok
//  ATTR_PAGE_FOOTERRIGHT ok
//  ATTR_PAGE_HEADERFIRST ok
//  ATTR_PAGE_FOOTERFIRST ok
// due to ScCellShell::ExecuteEdit
// due to ScTabViewShell::CreateRefDialogController
//  SCITEM_CONDFORMATDLGDATA ok
// due to SdDrawDocument::UpdatePageRelativeURLs
//  EE_FEATURE_FIELD ok
// due to SvxUnoMarkerTable::replaceByName
// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
// due to XLineStartItem::checkForUniqueItem
//  XATTR_LINESTART ok
// due to SvxUnoMarkerTable::replaceByName
// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
// due to XLineStartItem::checkForUniqueItem
//  XATTR_LINEEND ok
// due to SvxUnoNameItemTable
// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
// due to NameOrIndex::CheckNamedItem all derived from NameOrIndex
//  XATTR_FILLBITMAP ok
// due to SvxUnoNameItemTable
// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
//  XATTR_LINEDASH ok
// due to SvxUnoNameItemTable
// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
// due to NameOrIndex::CheckNamedItem all derived from NameOrIndex
//  XATTR_FILLGRADIENT ok
// due to SvxUnoNameItemTable
// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
//  XATTR_FILLHATCH ok
// due to SvxUnoNameItemTable
// due to SvxShape::setPropertyValueImpl/SvxShape::SetFillAttribute
//  XATTR_FILLFLOATTRANSPARENCE ok
// due to NamespaceIteratorImpl
//      -> needs to be evaluated
// due to SwCursorShell::GotoNxtPrvTOXMark
// due to SwDoc::GetTOIKeys
//  RES_TXTATR_TOXMARK ok
// due to SwDoc::GetRefMark
// due to SwDoc::CallEvent
// due to SwURLStateChanged::Notify
// due to SwHTMLWriter::CollectLinkTargets
// due to MSWordExportBase::CollectOutlineBookmarks
//  RES_TXTATR_INETFMT ok
// due to SwDoc::GetAllUsedDB
// due to lcl_FindInputField
// due to SwViewShell::IsAnyFieldInDoc
//  RES_TXTATR_FIELD ok
// due to SwDoc::GetAllUsedDB
// due to lcl_FindInputField
// due to SwViewShell::IsAnyFieldInDoc
//  RES_TXTATR_INPUTFIELD ok
// due to SwDoc::SetDefault
//  RES_PARATR_TABSTOP ok
// due to SwDoc::GetDocColors()
// due to RtfExport::OutColorTable
//  RES_CHRATR_COLOR ok
// due to SwDoc::GetDocColors()
//  RES_CHRATR_HIGHLIGHT ok
// due to SwDoc::GetDocColors()
//  RES_BACKGROUND ok
// due to SwNode::FindPageDesc
// due to SwPageNumberFieldType::ChangeExpansion
// due to SwFrame::GetVirtPageNum
//  RES_PAGEDESC ok
// due to SwAutoStylesEnumImpl::
//  RES_TXTATR_CJK_RUBY ok
// due to SwHTMLWriter::CollectLinkTargets
// due to MSWordExportBase::CollectOutlineBookmarks
//  RES_URL
// due to RtfExport::OutColorTable
//  RES_CHRATR_UNDERLINE ok
//  RES_CHRATR_OVERLINE ok
//  RES_CHRATR_BACKGROUND ok
//  RES_SHADOW ok
//  RES_BOX ok
//  RES_CHRATR_BOX ok
//  XATTR_FILLCOLOR ok
// due to wwFontHelper::InitFontTable
// due to SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl
//  RES_CHRATR_FONT ok
// due to wwFontHelper::InitFontTable
// due to SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl
//  RES_CHRATR_CJK_FONT ok
// due to wwFontHelper::InitFontTable
// due to SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl
//  RES_CHRATR_CTL_FONT
// due to SwXMLExport::exportDoc
//  RES_UNKNOWNATR_CONTAINER ok
//  RES_TXTATR_UNKNOWN_CONTAINER ok



#if OSL_DEBUG_LEVEL > 0
#include <map>
@@ -85,15 +249,6 @@ do { \
#define CHECK_SLOTS() do {} while (false)
#endif

/// clear array of PoolItem variants
/// after all PoolItems are deleted
/// or all ref counts are decreased
void SfxPoolItemArray_Impl::clear()
{
    maPoolItemSet.clear();
    maSortablePoolItems.clear();
}

sal_uInt16 SfxItemPool::GetFirstWhich() const
{
    return pImpl->mnStart;
@@ -124,35 +279,6 @@ sal_uInt16 SfxItemPool::GetSize_Impl() const
    return pImpl->mnEnd - pImpl->mnStart + 1;
}


bool SfxItemPool::CheckItemInPool(const SfxPoolItem *pItem) const
{
    DBG_ASSERT( pItem, "no 0-Pointer Surrogate" );
    DBG_ASSERT( !IsInvalidItem(pItem), "no Invalid-Item Surrogate" );
    DBG_ASSERT( !IsPoolDefaultItem(pItem), "no Pool-Default-Item Surrogate" );

    if ( !IsInRange(pItem->Which()) )
    {
        if ( pImpl->mpSecondary )
            return pImpl->mpSecondary->CheckItemInPool( pItem );
        SAL_WARN( "svl.items", "unknown Which-Id - don't ask me for surrogates, with ID/pos " << pItem->Which());
    }

    // Pointer on static or pool-default attribute?
    if( IsStaticDefaultItem(pItem) || IsPoolDefaultItem(pItem) )
        return true;

    SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[GetIndex_Impl(pItem->Which())];

    for ( auto p : rItemArr )
    {
        if ( p == pItem )
            return true;
    }
    SAL_WARN( "svl.items", "Item not in the pool, with ID/pos " << pItem->Which());
    return false;
}

const SfxPoolItem* SfxItemPool::GetPoolDefaultItem( sal_uInt16 nWhich ) const
{
    const SfxPoolItem* pRet;
@@ -169,21 +295,30 @@ const SfxPoolItem* SfxItemPool::GetPoolDefaultItem( sal_uInt16 nWhich ) const
}


bool SfxItemPool::IsItemPoolable_Impl( sal_uInt16 nPos ) const
bool SfxItemPool::NeedsPoolRegistration(sal_uInt16 nWhich) const
{
    return pItemInfos[nPos]._bPoolable;
    if (!IsInRange(nWhich))
    {
        // get to correct pool
        if (pImpl->mpSecondary)
            return pImpl->mpSecondary->NeedsPoolRegistration(nWhich);
        return false;
    }

    return NeedsPoolRegistration_Impl(nWhich - pImpl->mnStart);
}


bool SfxItemPool::IsItemPoolable( sal_uInt16 nWhich ) const
bool SfxItemPool::Shareable(sal_uInt16 nWhich) const
{
    for ( const SfxItemPool *pPool = this; pPool; pPool = pPool->pImpl->mpSecondary.get() )
    if (!IsInRange(nWhich))
    {
        if ( pPool->IsInRange(nWhich) )
            return pPool->IsItemPoolable_Impl( pPool->GetIndex_Impl(nWhich));
        // get to correct pool
        if (pImpl->mpSecondary)
            return pImpl->mpSecondary->Shareable(nWhich);
        return false;
    }
    DBG_ASSERT( !IsWhich(nWhich), "unknown which-id" );
    return false;

    return Shareable_Impl(nWhich - pImpl->mnStart);
}


@@ -227,7 +362,8 @@ SfxItemPool::SfxItemPool
                                           but no transfer of ownership */
) :
    pItemInfos(pInfo),
    pImpl( new SfxItemPool_Impl( this, rName, nStartWhich, nEndWhich ) )
    pImpl( new SfxItemPool_Impl( this, rName, nStartWhich, nEndWhich ) ),
    ppRegisteredSfxPoolItems(nullptr)
{
    pImpl->eDefMetric = MapUnit::MapTwip;

@@ -270,7 +406,8 @@ SfxItemPool::SfxItemPool
) :
    salhelper::SimpleReferenceObject(),
    pItemInfos(rPool.pItemInfos),
    pImpl( new SfxItemPool_Impl( this, rPool.pImpl->aName, rPool.pImpl->mnStart, rPool.pImpl->mnEnd ) )
    pImpl( new SfxItemPool_Impl( this, rPool.pImpl->aName, rPool.pImpl->mnStart, rPool.pImpl->mnEnd ) ),
    ppRegisteredSfxPoolItems(nullptr)
{
    pImpl->eDefMetric = rPool.pImpl->eDefMetric;

@@ -319,7 +456,8 @@ void SfxItemPool::SetDefaults( std::vector<SfxPoolItem*>* pDefaults )
            assert(  ((*pImpl->mpStaticDefaults)[n]->Which() == n + pImpl->mnStart)
                        && "items ids in pool-ranges and in static-defaults do not match" );
            (*pImpl->mpStaticDefaults)[n]->setStaticDefault();
            DBG_ASSERT( pImpl->maPoolItemArrays[n].empty(), "defaults with setitems with items?!" );
            DBG_ASSERT(nullptr == ppRegisteredSfxPoolItems || nullptr == ppRegisteredSfxPoolItems[n]
                || ppRegisteredSfxPoolItems[n]->empty(), "defaults with setitems with items?!" );
        }
    }
}
@@ -400,7 +538,9 @@ void SfxItemPool::ReleaseDefaults

SfxItemPool::~SfxItemPool()
{
    if ( !pImpl->maPoolItemArrays.empty() && !pImpl->maPoolDefaults.empty() )
    // Need to be deleted?
    // Caution: ppRegisteredSfxPoolItems is on-demand created and can be nullptr
    if ( nullptr != ppRegisteredSfxPoolItems || !pImpl->maPoolDefaults.empty() )
        Delete();

    if (pImpl->mpMaster != nullptr && pImpl->mpMaster != this)
@@ -421,26 +561,33 @@ void SfxItemPool::SetSecondaryPool( SfxItemPool *pPool )
    if ( pImpl->mpSecondary )
    {
#ifdef DBG_UTIL
        if (pImpl->mpStaticDefaults != nullptr && !pImpl->maPoolItemArrays.empty()
            && !pImpl->mpSecondary->pImpl->maPoolItemArrays.empty())
        if (nullptr != pImpl->mpStaticDefaults
            && nullptr != ppRegisteredSfxPoolItems
            && nullptr != pImpl->mpSecondary->ppRegisteredSfxPoolItems)
            // Delete() did not yet run?
        {
                // Does the Master have SetItems?
            bool bHasSetItems = false;
            for ( sal_uInt16 i = 0; !bHasSetItems && i < pImpl->mnEnd - pImpl->mnStart; ++i )
                bHasSetItems = dynamic_cast<const SfxSetItem *>((*pImpl->mpStaticDefaults)[i]) != nullptr;
            // Does the Master have SetItems?
            bool bHasSetItems(false);

            // Detached Pools must be empty
            bool bOK = bHasSetItems;
            for (auto const& rSecArray : pImpl->mpSecondary->pImpl->maPoolItemArrays)
            for (sal_uInt16 i(0); !bHasSetItems && i < pImpl->mnEnd - pImpl->mnStart; ++i)
            {
                if (!bOK)
                    break;
                if (rSecArray.size()>0)
                const SfxPoolItem* pStaticDefaultItem((*pImpl->mpStaticDefaults)[i]);
                bHasSetItems = pStaticDefaultItem->isSetItem();
            }

            if (bHasSetItems)
            {
                // Detached Pools must be empty
                registeredSfxPoolItems** ppSet(pImpl->mpSecondary->ppRegisteredSfxPoolItems);

                for (sal_uInt16 a(0); a < pImpl->mpSecondary->GetSize_Impl(); a++, ppSet++)
                {
                    SAL_WARN("svl.items", "old secondary pool: " << pImpl->mpSecondary->pImpl->aName
                                    << " of pool: " << pImpl->aName << " must be empty.");
                    break;
                    if (nullptr != *ppSet && (*ppSet)->size() != 0)
                    {
                        SAL_WARN("svl.items", "old secondary pool: " << pImpl->mpSecondary->pImpl->aName
                                        << " of pool: " << pImpl->aName << " must be empty.");
                        break;
                    }
                }
            }
        }
@@ -515,24 +662,26 @@ rtl::Reference<SfxItemPool> SfxItemPool::Clone() const
void SfxItemPool::Delete()
{
    // Already deleted?
    if (pImpl->maPoolItemArrays.empty() || pImpl->maPoolDefaults.empty())
    // Caution: ppRegisteredSfxPoolItems is on-demand created and can be nullptr
    if (nullptr == ppRegisteredSfxPoolItems && pImpl->maPoolDefaults.empty())
        return;

    // Inform e.g. running Requests
    pImpl->aBC.Broadcast( SfxHint( SfxHintId::Dying ) );

    // Iterate through twice: first for the SetItems.
    if (pImpl->mpStaticDefaults != nullptr) {
    if (nullptr != pImpl->mpStaticDefaults && nullptr != ppRegisteredSfxPoolItems)
    {
        for (size_t n = 0; n < GetSize_Impl(); ++n)
        {
            // *mpStaticDefaultItem could've already been deleted in a class derived
            // from SfxItemPool
            // This causes chaos in Itempool!
            const SfxPoolItem* pStaticDefaultItem = (*pImpl->mpStaticDefaults)[n];
            if (dynamic_cast<const SfxSetItem*>(pStaticDefaultItem))
            const SfxPoolItem* pStaticDefaultItem((*pImpl->mpStaticDefaults)[n]);
            if (pStaticDefaultItem->isSetItem() && nullptr != ppRegisteredSfxPoolItems[n])
            {
                // SfxSetItem found, remove PoolItems (and defaults) with same ID
                auto& rArray = pImpl->maPoolItemArrays[n];
                auto& rArray(*(ppRegisteredSfxPoolItems[n]));
                for (auto& rItemPtr : rArray)
                {
                    ReleaseRef(*rItemPtr, rItemPtr->GetRefCount()); // for RefCount check in dtor
@@ -553,18 +702,32 @@ void SfxItemPool::Delete()
        }
    }

    // now remove remaining PoolItems (and defaults) who didn't have SetItems
    for (auto& rArray : pImpl->maPoolItemArrays)
    if (nullptr != ppRegisteredSfxPoolItems)
    {
        for (auto& rItemPtr : rArray)
        registeredSfxPoolItems** ppSet(ppRegisteredSfxPoolItems);

        for (sal_uInt16 a(0); a < GetSize_Impl(); a++, ppSet++)
        {
            ReleaseRef(*rItemPtr, rItemPtr->GetRefCount()); // for RefCount check in dtor
            delete rItemPtr;
            if (nullptr != *ppSet)
            {
                for (auto& rCandidate : **ppSet)
                {
                    if (nullptr != rCandidate && !IsDefaultItem(rCandidate))
                    {
                        ReleaseRef(*rCandidate, rCandidate->GetRefCount()); // for RefCount check in dtor
                        delete rCandidate;
                    }
                }

                delete *ppSet;
                *ppSet = nullptr;
            }
        }
        rArray.clear();
        // let pImpl->DeleteItems() delete item arrays in maPoolItems

        delete[] ppRegisteredSfxPoolItems;
        ppRegisteredSfxPoolItems = nullptr;
    }
    pImpl->maPoolItemArrays.clear();

    // default items
    for (auto rItemPtr : pImpl->maPoolDefaults)
    {
@@ -631,189 +794,40 @@ void SfxItemPool::ResetPoolDefaultItem( sal_uInt16 nWhichId )
    }
}


const SfxPoolItem& SfxItemPool::PutImpl( const SfxPoolItem& rItem, sal_uInt16 nWhich, bool bPassingOwnership )
const SfxPoolItem& SfxItemPool::DirectPutItemInPoolImpl(const SfxPoolItem& rItem, sal_uInt16 nWhich, bool bPassingOwnership)
{
    if ( 0 == nWhich )
        nWhich = rItem.Which();

    // Find correct Secondary Pool
    bool bSID = IsSlot(nWhich);
    if ( !bSID && !IsInRange(nWhich) )
    {
        if ( pImpl->mpSecondary )
            return pImpl->mpSecondary->PutImpl( rItem, nWhich, bPassingOwnership );
        OSL_FAIL( "unknown WhichId - cannot put item" );
    }

    // SID ?
    if (bSID)
    {
        assert((rItem.Which() != nWhich ||
            !IsDefaultItem(&rItem) || rItem.isDeleteOnIdle())
                && "a non Pool Item is Default?!");
        SfxPoolItem *pPoolItem = rItem.Clone(pImpl->mpMaster);
        pPoolItem->SetWhich(nWhich);
        AddRef( *pPoolItem );
        if (bPassingOwnership)
            delete &rItem;
        return *pPoolItem;
    }

    assert(!pImpl->mpStaticDefaults ||
            typeid(rItem) == typeid(GetDefaultItem(nWhich)));

    const sal_uInt16 nIndex = GetIndex_Impl(nWhich);
    SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[nIndex];

    // Is this a 'poolable' item - ie. should we re-use and return
    // the same underlying item for equivalent (==) SfxPoolItems?
    if ( IsItemPoolable_Impl( nIndex ) )
    {
        // if is already in a pool, then it is worth checking if it is in this one.
        if ( IsPooledItem(&rItem) )
        {
            // 1. search for an identical pointer in the pool
            auto it = rItemArr.find(const_cast<SfxPoolItem *>(&rItem));
            if (it != rItemArr.end())
            {
                AddRef(rItem);
                assert(!bPassingOwnership && "can't be passing ownership and have the item already in the pool");
                return rItem;
            }
        }

        const SfxPoolItem* pFoundItem = nullptr;
        // 2. search for an item with matching attributes.
        if (rItem.IsSortable())
        {
            pFoundItem = rItemArr.findByLessThan(&rItem);
            if (pFoundItem)
                assert(*pFoundItem == rItem);
        }
        else if(rItem.HasLookup())
        {
            auto it = rItem.Lookup(rItemArr.begin(), rItemArr.end());
            if( it != rItemArr.end())
                pFoundItem = *it;
        }
        else
        {
            for (auto it = rItemArr.begin(); it != rItemArr.end(); ++it)
            {
                if (**it == rItem)
                {
                    pFoundItem = *it;
                    break;
                }
            }
        }
        if (pFoundItem)
        {
            assert((!bPassingOwnership || (&rItem != pFoundItem)) && "can't be passing ownership and have the item already in the pool");
            AddRef(*pFoundItem);
            if (bPassingOwnership)
                delete &rItem;
            return *pFoundItem;
        }
    }

    // 3. not found, so clone to insert into the pointer array.
    SfxPoolItem* pNewItem;
    if (bPassingOwnership)
    {
#ifndef NDEBUG
        if (auto pSetItem = dynamic_cast<const SfxSetItem*>(&rItem))
            assert(pSetItem->GetItemSet().GetPool() == pImpl->mpMaster && "can't pass ownership of SfxSetItem, unless they have been cloned to the master pool");
#ifdef DBG_UTIL
    nAllDirectlyPooledSfxPoolItemCount++;
    nRemainingDirectlyPooledSfxPoolItemCount++;
#endif
        pNewItem = const_cast<SfxPoolItem*>(&rItem);
    }
    else
        pNewItem = rItem.Clone(pImpl->mpMaster);
    pNewItem->SetWhich(nWhich);
    assert(typeid(rItem) == typeid(*pNewItem) && "SfxItemPool::Put(): unequal types, no Clone() override?");
#ifndef NDEBUG
    if (dynamic_cast<const SfxSetItem*>(&rItem) == nullptr)
    {
        assert((!IsItemPoolable(nWhich) || rItem == *pNewItem)
            && "SfxItemPool::Put(): unequal items: no operator== override?");
        assert((!IsItemPoolable(*pNewItem) || *pNewItem == rItem)
            && "SfxItemPool::Put(): unequal items: no operator== override?");
    }
#endif
    AddRef( *pNewItem );

    // 4. finally insert into the pointer array
    rItemArr.insert( pNewItem );
    return *pNewItem;
    // make sure to use 'master'-pool, that's the one used by SfxItemSets
    return *implCreateItemEntry(*GetMasterPool(), &rItem, nWhich, bPassingOwnership, true);
}

void SfxItemPool::Remove( const SfxPoolItem& rItem )
void SfxItemPool::DirectRemoveItemFromPool(const SfxPoolItem& rItem)
{
    assert(!IsPoolDefaultItem(&rItem) && "cannot remove Pool Default");
#ifdef DBG_UTIL
    nRemainingDirectlyPooledSfxPoolItemCount--;
#endif

    // Find correct Secondary Pool
    const sal_uInt16 nWhich = rItem.Which();
    bool bSID = IsSlot(nWhich);
    if ( !bSID && !IsInRange(nWhich) )
    {
        if ( pImpl->mpSecondary )
        {
            pImpl->mpSecondary->Remove( rItem );
            return;
        }
        OSL_FAIL( "unknown WhichId - cannot remove item" );
    }

    // SID ?
    if ( bSID )
    {
        assert(!IsDefaultItem(&rItem) && "a non Pool Item is Default?!");
        if ( 0 == ReleaseRef(rItem) )
        {
            delete &rItem;
        }
        return;
    }

    const sal_uInt16 nIndex = GetIndex_Impl(nWhich);
    // Static Defaults are just there
    if ( IsStaticDefaultItem(&rItem) &&
         &rItem == (*pImpl->mpStaticDefaults)[nIndex])
        return;

    // moved below StaticDefaultItem detection - StaticDefaultItems
    // do not need a RefCnt of SFX_ITEMS_SPECIAL (0xffffffff) anymore
    assert(rItem.GetRefCount() && "RefCount == 0, Remove impossible");

    // Find Item in own Pool
    SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[nIndex];

    auto it = rItemArr.find(const_cast<SfxPoolItem *>(&rItem));
    if (it != rItemArr.end())
    {
        if ( rItem.GetRefCount() ) //!
            ReleaseRef( rItem );
        else
        {
            assert(false && "removing Item without ref");
        }

        // FIXME: Hack, for as long as we have problems with the Outliner
        // See other MI-REF
        if ( 0 == rItem.GetRefCount() && nWhich < 4000 )
        {
            rItemArr.erase(it);
            delete &rItem;
        }

        return;
    }

    // not found
    assert(false && "removing Item not in Pool");
    // make sure to use 'master'-pool, that's the one used by SfxItemSets
    implCleanupItemEntry(*GetMasterPool(), &rItem);
    return;
}

void SfxItemPool::newItem_Callback(const SfxPoolItem& rItem) const
{
    if (!IsInRange(rItem.Which()) && pImpl->mpSecondary)
        pImpl->mpSecondary->newItem_Callback(rItem);
}

bool SfxItemPool::newItem_UseDirect(const SfxPoolItem& rItem) const
{
    if (!IsInRange(rItem.Which()) && pImpl->mpSecondary)
        return pImpl->mpSecondary->newItem_UseDirect(rItem);
    return false;
}

const SfxPoolItem& SfxItemPool::GetDefaultItem( sal_uInt16 nWhich ) const
{
@@ -893,51 +907,93 @@ const SfxPoolItem *SfxItemPool::GetItem2Default(sal_uInt16 nWhich) const
    return (*pImpl->mpStaticDefaults)[ GetIndex_Impl(nWhich) ];
}

SfxItemPool::Item2Range SfxItemPool::GetItemSurrogates(sal_uInt16 nWhich) const
#ifdef DBG_UTIL
static void warnForMissingPoolRegistration(const SfxItemPool& rPool, sal_uInt16 nWhich)
{
    static const o3tl::sorted_vector<SfxPoolItem*> EMPTY;
    if (!rPool.NeedsPoolRegistration(nWhich))
        SAL_INFO("svl.items", "ITEM: ItemSurrogate requested for WhichID " << nWhich <<
        " class " << typeid(rPool.GetDefaultItem(nWhich)).name() <<
        ": needs _bNeedsPoolRegistration==true in SfxItemInfo for that slot");
}
#endif

    if ( !IsInRange(nWhich) )
const registeredSfxPoolItems& SfxItemPool::GetItemSurrogates(sal_uInt16 nWhich) const
{
    static const registeredSfxPoolItems EMPTY;

    if (!IsInRange(nWhich))
    {
        if ( pImpl->mpSecondary )
            return pImpl->mpSecondary->GetItemSurrogates( nWhich );
        assert(false && "unknown WhichId - cannot resolve surrogate");
        return { EMPTY.end(), EMPTY.end() };
        if (pImpl->mpSecondary)
            return pImpl->mpSecondary->GetItemSurrogates(nWhich);
        return EMPTY;
    }

    SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[GetIndex_Impl(nWhich)];
    return { rItemArr.begin(), rItemArr.end() };
    if (nullptr == ppRegisteredSfxPoolItems)
    {
#ifdef DBG_UTIL
        warnForMissingPoolRegistration(*this, nWhich);
#endif
        return EMPTY;
    }

    registeredSfxPoolItems* pSet(ppRegisteredSfxPoolItems[nWhich - pImpl->mnStart]);

    if (nullptr == pSet)
    {
#ifdef DBG_UTIL
        warnForMissingPoolRegistration(*this, nWhich);
#endif
        return EMPTY;
    }

    return *pSet;
}

/* This is only valid for SfxPoolItem that override IsSortable and operator< */
std::vector<const SfxPoolItem*> SfxItemPool::FindItemSurrogate(sal_uInt16 nWhich, SfxPoolItem const & rSample) const
{
    static const std::vector<const SfxPoolItem*> EMPTY;

    if (nullptr == ppRegisteredSfxPoolItems)
        return EMPTY;

    if ( !IsInRange(nWhich) )
    {
        if ( pImpl->mpSecondary )
            return pImpl->mpSecondary->FindItemSurrogate( nWhich, rSample );
        assert(false && "unknown WhichId - cannot resolve surrogate");
        return std::vector<const SfxPoolItem*>();
        return EMPTY;
    }

    SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[GetIndex_Impl(nWhich)];
    return rItemArr.findSurrogateRange(&rSample);
}
    // get index (must exist due to checks above)
    const sal_uInt16 nIndex(rSample.Which() - pImpl->mnStart);

sal_uInt32 SfxItemPool::GetItemCount2(sal_uInt16 nWhich) const
{
    if ( !IsInRange(nWhich) )
    if (nullptr == ppRegisteredSfxPoolItems)
    {
        if ( pImpl->mpSecondary )
            return pImpl->mpSecondary->GetItemCount2( nWhich );
        assert(false && "unknown WhichId - cannot resolve surrogate");
        return 0;
#ifdef DBG_UTIL
        warnForMissingPoolRegistration(*this, nWhich);
#endif
        return EMPTY;
    }

    SfxPoolItemArray_Impl& rItemArr = pImpl->maPoolItemArrays[GetIndex_Impl(nWhich)];
    return rItemArr.size();
}
    // get registeredSfxPoolItems container
    registeredSfxPoolItems* pSet(ppRegisteredSfxPoolItems[nIndex]);

    if (nullptr == pSet)
    {
#ifdef DBG_UTIL
        warnForMissingPoolRegistration(*this, nWhich);
#endif
        return EMPTY;
    }

    std::vector<const SfxPoolItem*> rv;

    for (const SfxPoolItem* p : *pSet)
        if (rSample == *p)
            rv.push_back(p);

    return rv;
}

sal_uInt16 SfxItemPool::GetWhich( sal_uInt16 nSlotId, bool bDeep ) const
{
@@ -1002,12 +1058,219 @@ sal_uInt16 SfxItemPool::GetTrueSlotId( sal_uInt16 nWhich ) const
    return pItemInfos[nWhich - pImpl->mnStart]._nSID;
}

void SfxItemPool::tryRegisterSfxPoolItem(const SfxPoolItem& rItem, bool bPoolDirect)
{
    assert(rItem.Which() != 0);

    if (IsSlot(rItem.Which()))
        // do not register SlotItems
        return;

    if (rItem.isRegisteredAtPool())
        // already registered, done (should not happen)
        return;

    if (!IsInRange(rItem.Which()))
    {
        // get to the right pool
        if (pImpl->mpSecondary)
        {
            pImpl->mpSecondary->tryRegisterSfxPoolItem(rItem, bPoolDirect);
            return;
        }

        return;
    }

    // get index (must exist due to checks above)
    const sal_uInt16 nIndex(rItem.Which() - pImpl->mnStart);
    bool bRegisterItem(bPoolDirect);

    if (!bRegisterItem)
    {
        if (g_bItemClassicMode)
        {
            // classic mode: register in general *all* items
            // ...but only shareable ones: for non-shareable registering for re-use
            // makes no sense
            bRegisterItem = Shareable_Impl(nIndex);
        }
        else
        {
            // experimental mode: only register items that are defined to be registered
            bRegisterItem = NeedsPoolRegistration_Impl(nIndex);
        }
    }

    if (bRegisterItem)
        doRegisterSfxPoolItem(rItem);
}

void SfxItemPool::doRegisterSfxPoolItem(const SfxPoolItem& rItem)
{
    assert(rItem.Which() != 0);

    if (IsSlot(rItem.Which()))
        // do not register SlotItems
        return;

    if (rItem.isRegisteredAtPool())
        // already registered, done
        return;

    if (nullptr == ppRegisteredSfxPoolItems)
        // on-demand allocate array of registeredSfxPoolItems and init to nullptr
        ppRegisteredSfxPoolItems = new registeredSfxPoolItems*[GetSize_Impl()]{};

    // get correct registeredSfxPoolItems
    const sal_uInt16 nIndex(rItem.Which() - pImpl->mnStart);
    registeredSfxPoolItems* pSet(ppRegisteredSfxPoolItems[nIndex]);

    if (nullptr == pSet)
        // on-demand allocate
        ppRegisteredSfxPoolItems[nIndex] = pSet = new registeredSfxPoolItems;

    // insert to registeredSfxPoolItems and set flag at Item
    pSet->insert(&rItem);
    const_cast<SfxPoolItem&>(rItem).setRegisteredAtPool(true);
}

void SfxItemPool::unregisterSfxPoolItem(const SfxPoolItem& rItem)
{
    if (!rItem.isRegisteredAtPool())
        // Item is not registered, done
        return;

    if (!IsInRange(rItem.Which()))
    {
        // get to the right pool
        if (pImpl->mpSecondary)
        {
            pImpl->mpSecondary->unregisterSfxPoolItem(rItem);
            return;
        }

        assert(false && "unknown WhichId - cannot execute unregisterSfxPoolItem");
        return;
    }

    // we need a valid WhichID and the array of containers has to exist
    assert(rItem.Which() != 0);
    assert(nullptr != ppRegisteredSfxPoolItems);

    // get index (must exist due to checks above)
    const sal_uInt16 nIndex(rItem.Which() - pImpl->mnStart);

    // a valid registeredSfxPoolItems container has to exist
    registeredSfxPoolItems* pSet(ppRegisteredSfxPoolItems[nIndex]);
    assert(nullptr != pSet);

    // remove registered Item and reset flag at Item
    pSet->erase(&rItem);
    const_cast<SfxPoolItem&>(rItem).setRegisteredAtPool(false);
}

bool SfxItemPool::isSfxPoolItemRegisteredAtThisPool(const SfxPoolItem& rItem) const
{
    if (!rItem.isRegisteredAtPool())
        // Item is not registered at all, so also not at this Pool
        return false;

    if (IsSlot(rItem.Which()))
        // do not check being registered for SlotItems
        return false;

    if (!IsInRange(rItem.Which()))
    {
        // get to the right pool
        if (pImpl->mpSecondary)
            return pImpl->mpSecondary->isSfxPoolItemRegisteredAtThisPool(rItem);
        return false;
    }

    // we need a valid WhichID
    assert(rItem.Which() != 0);

    if (nullptr == ppRegisteredSfxPoolItems)
        // when no array of containers exists the Item is not registered
        return false;

    // get index (must exist due to checks above)
    const sal_uInt16 nIndex(rItem.Which() - pImpl->mnStart);

    // get registeredSfxPoolItems container
    registeredSfxPoolItems* pSet(ppRegisteredSfxPoolItems[nIndex]);

    if (nullptr == pSet)
        // when no registeredSfxPoolItems container exists the Item is not registered
        return false;

    // test if Item is registered
    return pSet->find(&rItem) != pSet->end();
}

const SfxPoolItem* SfxItemPool::tryToGetEqualItem(const SfxPoolItem& rItem, sal_uInt16 nWhich) const
{
    if (IsSlot(nWhich))
        // SlotItems are not registered @pool and not in any range
        return nullptr;

    if (!IsInRange(nWhich))
    {
        // get to the right pool
        if (pImpl->mpSecondary)
            return pImpl->mpSecondary->tryToGetEqualItem(rItem, nWhich);
        return nullptr;
    }

    if (nullptr == ppRegisteredSfxPoolItems)
        // no Items at all
        return nullptr;

    // get index (must exist due to checks above)
    const sal_uInt16 nIndex(nWhich - pImpl->mnStart);

    if (!Shareable_Impl(nIndex))
        // not shareable
        return nullptr;

    // get registeredSfxPoolItems container
    registeredSfxPoolItems* pSet(ppRegisteredSfxPoolItems[nIndex]);

    if (nullptr == pSet)
        // no registeredSfxPoolItems for this WhichID
        return nullptr;

    for (const auto& rCandidate : *pSet)
        if (*rCandidate == rItem)
            return rCandidate;

    return nullptr;
}

void SfxItemPool::dumpAsXml(xmlTextWriterPtr pWriter) const
{
    (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SfxItemPool"));
    for (auto const & rArray : pImpl->maPoolItemArrays)
        for (auto const & rItem : rArray)
            rItem->dumpAsXml(pWriter);

    if (nullptr != ppRegisteredSfxPoolItems)
    {
        registeredSfxPoolItems** ppSet(ppRegisteredSfxPoolItems);

        for (sal_uInt16 a(0); a < GetSize_Impl(); a++, ppSet++)
        {
            if (nullptr != *ppSet)
            {
                for (auto& rCandidate : **ppSet)
                {
                    if (nullptr != rCandidate)
                    {
                        rCandidate->dumpAsXml(pWriter);
                    }
                }
            }
        }
    }

    (void)xmlTextWriterEndElement(pWriter);
}

diff --git a/svl/source/items/itemset.cxx b/svl/source/items/itemset.cxx
index 62f4df0..c3faeca 100644
--- a/svl/source/items/itemset.cxx
+++ b/svl/source/items/itemset.cxx
@@ -42,6 +42,11 @@ static size_t nUsedSfxItemSetCount(0);
size_t getAllocatedSfxItemSetCount() { return nAllocatedSfxItemSetCount; }
size_t getUsedSfxItemSetCount() { return nUsedSfxItemSetCount; }
#endif
// NOTE: Only needed for one Item in SC (see notes below for
// ScPatternAttr/ATTR_PATTERN). Still keep it so that when errors
// come up to this change be able to quickly check using the
// fallback flag 'ITEM_CLASSIC_MODE'
static bool g_bItemClassicMode(getenv("ITEM_CLASSIC_MODE"));

/**
 * Ctor for a SfxItemSet with exactly the Which Ranges, which are known to
@@ -123,65 +128,235 @@ SfxItemSet::SfxItemSet(SfxItemPool& pool, WhichRangesContainer wids)
    assert(svl::detail::validRanges2(m_pWhichRanges));
}

SfxPoolItem const* SfxItemSet::implCreateItemEntry(SfxPoolItem const* pSource, sal_uInt16 nWhich, bool bItemIsSetMember, bool bPassingOwnership)
SfxPoolItem const* implCreateItemEntry(SfxItemPool& rPool, SfxPoolItem const* pSource, sal_uInt16 nWhich, bool bPassingOwnership, bool bPoolDirect)
{
    if (nullptr == pSource)
        // SfxItemState::UNKNOWN aka current default (nullptr)
        // just use nullptr
        // just use/return nullptr
        return pSource;

    if (IsInvalidItem(pSource))
        // SfxItemState::DONTCARE aka invalid item
        // just use pSource which is INVALID_POOL_ITEM
        // just use pSource which equals INVALID_POOL_ITEM
        return pSource;

    if (pSource->isNewItemCallback() && rPool.GetMasterPool()->newItem_UseDirect(*pSource))
        // exceptional handling for *some* items, see SC
        // (do not copy item: use directly, it is a pool default)
        return pSource;

    // CAUTION: static default items are not *that* static as it seems
    // (or: should be). If they are freed with the Pool (see
    // ::ReleaseDefaults) they will be deleted. If the target pool is
    // different from the source pool static default items from the
    // source pool can be used that then might be deleted (sigh).
    // A solution would be to change all pools to really work on
    // static instances of default items. Another one would be to know
    // here that the targetPool != sourcePool, so maybe extend
    // bItemIsSetMember -> bSamePool.
    // A good test for this is CppunitTest_chart2_uichart/testTdf98690.
    // Until solving/cleaning up we unfortunately *have* to continue
    // to clone static default items...

    // ::ReleaseDefaults) they will be deleted. Same is true for
    // dynamic defaults. Thus currently no default can be shared
    // at all since these may be deleted with the pool owning them.
    // That these are not shared but cloned is ensured by those
    // having a default RefCount of zero, so these are used merely as
    // templates.
    // if (IsStaticDefaultItem(pSource))
    //     // these Items are owned by the pool and not ref-counted.
    //     // they will exist while the pool exists, and thus the
    //     // ItemSet (this).
    //     return pSource;

    if (0 == pSource->Which())
        // These *should* be SfxVoidItem(0) the only Items with 0 == WhichID,
        // these need to be cloned
        // these need to be cloned (currently...)
        return pSource->Clone();

    if (pSource->isShareable() && bItemIsSetMember && IsPooledItem(pSource))//!IsPoolDefaultItem(pSource) && GetPool()->IsItemPoolable(*pSource))
    // get correct target WhichID
    if (0 == nWhich)
        nWhich = pSource->Which();

    if (SfxItemPool::IsSlot(nWhich))
    {
        // shortcut: if we know that the Item is already a member
        // of another SfxItemSet we can just copy the pointer and increase RefCount
        // SlotItems were always cloned in original (even when bPassingOwnership),
        // so do that here, too (but without bPassingOwnership).
        // They do not need to be registerd at pool (actually impossible, pools
        // do not have entries for SlotItems) so handle here early
        if (!bPassingOwnership)
            pSource = pSource->Clone(rPool.GetMasterPool());

        if (pSource->Which() != nWhich)
            const_cast<SfxPoolItem*>(pSource)->SetWhich(nWhich);

        pSource->AddRef();
        return pSource;
    }

    // assign via Pool
    return &GetPool()->PutImpl(*pSource, 0 == nWhich ? pSource->Which() : nWhich, bPassingOwnership);
    // get the pool with which ItemSets have to work, plus get the
    // pool at which the WhichID is defined, so calls to it do not
    // have to do this repeatedly
    SfxItemPool* pMasterPool(rPool.GetMasterPool());
    assert(nullptr != pMasterPool);
    SfxItemPool* pTargetPool(pMasterPool);
    while (!pTargetPool->IsInRange(nWhich))
        pTargetPool = pTargetPool->GetSecondaryPool();

    // if this goes wrong, an Item with invalid ID for this pool is
    // processed. This is not allowed (and should not happen, e.g.
    // ItemSets already have WhichRanges that are checked against
    // their Pool)
    if (nullptr == pTargetPool)
    {
        assert(false);
        return pSource;
    }

    // CAUTION: Shareable_Impl and NeedsPoolRegistration_Impl
    // use index, not WhichID (one more reason to change the Pools)
    const sal_uInt16 nIndex(pTargetPool->GetIndex_Impl(nWhich));

    // the Item itself is shareable when it already is used somewhere
    // which is equlivalent to be referenced already. IsPooledItem also
    // checked for SFX_ITEMS_MAXREF, that is not needed here. Use a
    // fake 'while' loop and 'break' to make this better readable

    // only try to share items that are already shared somehow, else
    // these items are probably not (heap) item-ptr's (but on the
    // stack or else)
    while(pSource->GetRefCount() > 0)
    {
        if (pSource->Which() != nWhich)
            // If the target WhichID differs from the WhichID of a shared Item
            // the item needs to be cloned. This happens, e.g. in
            // ScPatternAttr::GetFromEditItemSet existing items with WhichIDs
            // from EditEngine get set at a SetItem's ItemSet with different
            // target ranges (e.g. look for ATTR_FONT_UNDERLINE)
            break;

        if (!pTargetPool->Shareable_Impl(nIndex))
            // not shareable, done
            break;

        // SfxSetItems cannot be shared if they are in/use another pool
        if (pSource->isSetItem() && static_cast<const SfxSetItem*>(pSource)->GetItemSet().GetPool() != pMasterPool)
            break;

        // If the Item is registered it is pool-dependent, so do not share when
        // it is registered but not at this pool
        if (pSource->isRegisteredAtPool() && !pTargetPool->isSfxPoolItemRegisteredAtThisPool(*pSource))
            break;

        // If we get here we can share the Item
        pSource->AddRef();
        return pSource;
    }

    // classic mode: try finding already existing item
    // NOTE: bPoolDirect currently required due to DirectPutItemInPool and the
    //   self-handled Item ScPatternAttr/ATTR_PATTERN in SC, else e.g.
    //   testIteratorsDefPattern will fail in line 1306
    // NOTE: the UnitTest testIteratorsDefPattern claims that that Item "can be
    //   edited by the user" which explains why it breaks so many rules for Items,
    //   it behaves like an alien. That Item in the SC Pool claims to be a
    //   'StaticDefault' and gets changed (..?)
    // NOTE: despite 1st thinking that this can be limited to ScPatternAttr/
    //   ATTR_PATTERN it also has to be applied to the range
    //   [ATTR_PATTERN_START, ATTR_PATTERN_END] *used* by ATTR_PATTERN, plus
    //   it, so it's [100 .. 155] and [156] in SC. For now, just use bPoolDirect.
    //   This needs to be cleaned-up somehow anyways

    // only do this if classic mode or required (calls from Pool::Direct*)
    while(g_bItemClassicMode || bPoolDirect)
    {
        if (!pTargetPool->Shareable_Impl(nIndex))
            // not shareable, so no need to search for identical item
            break;

        // try to get equal Item. This is the expensive part...
        const SfxPoolItem* pExisting(pTargetPool->tryToGetEqualItem(*pSource, nWhich));

        if (nullptr == pExisting)
            // none found, done
            break;

        if (0 == pExisting->GetRefCount())
            // do not share not-yet shared Items (should not happen)
            break;

        if (bPassingOwnership)
            // need to cleanup if we are offered to own pSource
            delete pSource;

        // If we get here we can share the found Item
        pExisting->AddRef();
        return pExisting;
    }

    // check if the handed over and to be directly used item is a
    // SfxSetItem, that would make it pool-dependent. It then must have
    // the same target-pool, ensure that by the cost of cloning it
    // (should not happen)
    if (bPassingOwnership
        && pSource->isSetItem()
        && static_cast<const SfxSetItem*>(pSource)->GetItemSet().GetPool() != pMasterPool)
    {
        const SfxPoolItem* pOld(pSource);
        pSource = pSource->Clone(pMasterPool);
        delete pOld;
    }

    // when we reach this line we know that we have to add/create a new item. If
    // bPassingOwnership is given just use the item, else clone it
    if (!bPassingOwnership)
        pSource = pSource->Clone(pMasterPool);

    // ensure WhichID @Item
    if (pSource->Which() != nWhich)
        const_cast<SfxPoolItem*>(pSource)->SetWhich(nWhich);

    // increase RefCnt 0->1
    pSource->AddRef();

    // Unfortunately e,g, SC does 'special' things for some new Items,
    // so we need to give the opportunity for this. To limit this to
    // the needed cases, use m_bNewItemCallback flag at item
    if (pSource->isNewItemCallback())
        pMasterPool->newItem_Callback(*pSource);

    // try to register @Pool (only needed if not yet registered)
    if (!pSource->isRegisteredAtPool())
    {
        if (!bPoolDirect) // re-use bPoolDirect
        {
            if (g_bItemClassicMode)
            {
                // in classic mode register only/all shareable items
                bPoolDirect = pTargetPool->Shareable_Impl(nIndex);
            }
            else
            {
                // in new mode register only/all items marked as need to be registered
                bPoolDirect = pTargetPool->NeedsPoolRegistration_Impl(nIndex);
            }
        }

        if (bPoolDirect)
            pTargetPool->doRegisterSfxPoolItem(*pSource);
    }

    return pSource;
}

void SfxItemSet::implCleanupItemEntry(SfxPoolItem const* pSource)
void implCleanupItemEntry(SfxItemPool& rPool, SfxPoolItem const* pSource)
{
    if (nullptr == pSource                  // no entry, done
        || IsInvalidItem(pSource)           // nothing to do for invalid item entries
        || IsStaticDefaultItem(pSource))    // static default items are owned by the pool, nothing to do
    {
    if (nullptr == pSource)
        // no entry, done
        return;
    }

    if (IsInvalidItem(pSource))
        // nothing to do for invalid item entries
        return;

    if (pSource->isNewItemCallback() && rPool.GetMasterPool()->newItem_UseDirect(*pSource))
        // exceptional handling for *some* items, see SC
        // do not delete Item, it is a pool default
        return;

    if (0 == pSource->Which())
    {
        // de-register when registered @pool
        if (pSource->isRegisteredAtPool())
            rPool.unregisterSfxPoolItem(*pSource);

        // These *should* be SfxVoidItem(0) the only Items with 0 == WhichID
        // and need to be deleted
        delete pSource;
@@ -195,8 +370,20 @@ void SfxItemSet::implCleanupItemEntry(SfxPoolItem const* pSource)
        return;
    }

    // Delete from Pool
    GetPool()->Remove(*pSource);
    if (IsDefaultItem(pSource))
        // default items (static and dynamic) are owned by the pool, do not delete
        return;

    // decrease RefCnt before deleting (destructor asserts for it and that's
    // good to find other errors)
    pSource->ReleaseRef();

    // de-register before deletion when registered @pool
    if (pSource->isRegisteredAtPool())
        rPool.unregisterSfxPoolItem(*pSource);

    // delete Item
    delete pSource;
}

SfxItemSet::SfxItemSet( const SfxItemSet& rASet )
@@ -218,16 +405,23 @@ SfxItemSet::SfxItemSet( const SfxItemSet& rASet )
        return;
    }

    if (0 == rASet.Count())
    {
        // no Items set in source ItemSet, allocate new array
        // *plus* init to nullptr
        m_ppItems = new const SfxPoolItem* [TotalCount()]{};
        return;
    }

    // allocate new array (no need to initialize, will be done below)
    m_ppItems = new const SfxPoolItem* [TotalCount()];

    // Copy attributes
    SfxPoolItem const** ppDst(m_ppItems);
    const bool bSamePool(GetPool() == rASet.GetPool());

    for (const auto& rSource : rASet)
    {
        *ppDst = implCreateItemEntry(rSource, 0, bSamePool, false);
        *ppDst = implCreateItemEntry(*GetPool(), rSource, 0, false, false);
        ppDst++;
    }

@@ -339,7 +533,7 @@ sal_uInt16 SfxItemSet::ClearSingleItem_ForOffset( sal_uInt16 nOffset )
    }

    // cleanup item & reset ptr
    implCleanupItemEntry(*aEntry);
    implCleanupItemEntry(*GetPool(), *aEntry);
    *aEntry = nullptr;

    return 1;
@@ -359,7 +553,7 @@ sal_uInt16 SfxItemSet::ClearAllItemsImpl()
            m_aCallback(rCandidate, nullptr);
        }

        implCleanupItemEntry(rCandidate);
        implCleanupItemEntry(*GetPool(), rCandidate);
    }

    // remember count before resetting it, that is the retval
@@ -460,7 +654,7 @@ bool SfxItemSet::HasItem(sal_uInt16 nWhich, const SfxPoolItem** ppItem) const
    return bRet;
}

const SfxPoolItem* SfxItemSet::PutImpl(const SfxPoolItem& rItem, sal_uInt16 nWhich, bool bItemIsSetMember, bool bPassingOwnership)
const SfxPoolItem* SfxItemSet::PutImpl(const SfxPoolItem& rItem, sal_uInt16 nWhich, bool bPassingOwnership)
{
    bool bActionNeeded(0 != nWhich);
    sal_uInt16 nOffset(INVALID_WHICHPAIR_OFFSET);
@@ -492,18 +686,8 @@ const SfxPoolItem* SfxItemSet::PutImpl(const SfxPoolItem& rItem, sal_uInt16 nWhi
        }
        else
        {
            if (*aEntry == &rItem)
            {
                // Same Item already present (ptr compare)?
                bActionNeeded = false;
            }
            else if (typeid(**aEntry) == typeid(rItem) && **aEntry == rItem)
            {
                // Same value already present (content compare)?
                // NOTE: we can now use typeid since we do not have (-1)
                // anymore for Invalid state -> safe
                bActionNeeded = false;
            }
            // compare items, evtl. containing content compare
            bActionNeeded = !SfxPoolItem::areSame(**aEntry, rItem);
        }
    }

@@ -518,7 +702,7 @@ const SfxPoolItem* SfxItemSet::PutImpl(const SfxPoolItem& rItem, sal_uInt16 nWhi
    }

    // prepare new entry
    SfxPoolItem const* pNew(implCreateItemEntry(&rItem, nWhich, bItemIsSetMember, bPassingOwnership));
    SfxPoolItem const* pNew(implCreateItemEntry(*GetPool(), &rItem, nWhich, bPassingOwnership, false));

    // Notification-Callback
    if(m_aCallback)
@@ -527,7 +711,7 @@ const SfxPoolItem* SfxItemSet::PutImpl(const SfxPoolItem& rItem, sal_uInt16 nWhi
    }

    // cleanup old entry & set entry at m_ppItems array
    implCleanupItemEntry(*aEntry);
    implCleanupItemEntry(*GetPool(), *aEntry);
    *aEntry = pNew;

    return pNew;
@@ -541,7 +725,6 @@ bool SfxItemSet::Put(const SfxItemSet& rSource, bool bInvalidAsDefault)

    const_iterator aSource(rSource.begin());
    sal_uInt16 nNumberToGo(rSource.Count());
    const bool bSamePool(GetPool() == rSource.GetPool());
    bool bRetval(false);

    // iterate based on WhichIDs to have it available for evtl. PutImpl calls
@@ -566,7 +749,7 @@ bool SfxItemSet::Put(const SfxItemSet& rSource, bool bInvalidAsDefault)
                }
                else
                {
                    bRetval |= nullptr != PutImpl(**aSource, nWhich, bSamePool, false);
                    bRetval |= nullptr != PutImpl(**aSource, nWhich, false);
                }
            }

@@ -605,7 +788,6 @@ void SfxItemSet::PutExtended
{
    // don't "optimize" with "if( rSource.Count()" because of dontcare + defaults
    const_iterator aSource(rSource.begin());
    const bool bSamePool(GetPool() == rSource.GetPool());

    for (const WhichPair& rPair : rSource.GetRanges())
    {
@@ -619,7 +801,7 @@ void SfxItemSet::PutExtended
                    switch (eDontCareAs)
                    {
                        case SfxItemState::SET:
                            PutImpl(rSource.GetPool()->GetDefaultItem(nWhich), nWhich, false, false);
                            PutImpl(rSource.GetPool()->GetDefaultItem(nWhich), nWhich, false);
                            break;

                        case SfxItemState::DEFAULT:
@@ -637,7 +819,7 @@ void SfxItemSet::PutExtended
                else
                {
                    // Item is set:
                    PutImpl(**aSource, nWhich, bSamePool, false);
                    PutImpl(**aSource, nWhich, false);
                }
            }
            else
@@ -646,7 +828,7 @@ void SfxItemSet::PutExtended
                switch (eDefaultAs)
                {
                    case SfxItemState::SET:
                        PutImpl(rSource.GetPool()->GetDefaultItem(nWhich), nWhich, false, false);
                        PutImpl(rSource.GetPool()->GetDefaultItem(nWhich), nWhich, false);
                        break;

                    case SfxItemState::DEFAULT:
@@ -1111,7 +1293,7 @@ void SfxItemSet::Differentiate(const SfxItemSet& rSet)
 * dontcare    unknown     !=      sal_True            -           -           -
 * unknown     unknown     !=      sal_True            -           -           -
 */
void SfxItemSet::MergeItem_Impl(const SfxPoolItem **ppFnd1, const SfxPoolItem *pFnd2, bool bItemIsSetMember, bool bIgnoreDefaults)
void SfxItemSet::MergeItem_Impl(const SfxPoolItem **ppFnd1, const SfxPoolItem *pFnd2, bool bIgnoreDefaults)
{
    assert(ppFnd1 != nullptr && "Merging to 0-Item");

@@ -1129,7 +1311,7 @@ void SfxItemSet::MergeItem_Impl(const SfxPoolItem **ppFnd1, const SfxPoolItem *p

        else if ( pFnd2 && bIgnoreDefaults )
            // Decision table: default, set, doesn't matter, sal_True
            *ppFnd1 = implCreateItemEntry(pFnd2, 0, bItemIsSetMember, false);
            *ppFnd1 = implCreateItemEntry(*GetPool(), pFnd2, 0, false, false);
            // *ppFnd1 = &GetPool()->Put( *pFnd2 );

        if ( *ppFnd1 )
@@ -1146,7 +1328,7 @@ void SfxItemSet::MergeItem_Impl(const SfxPoolItem **ppFnd1, const SfxPoolItem *p
                 **ppFnd1 != GetPool()->GetDefaultItem((*ppFnd1)->Which()) )
            {
                // Decision table: set, default, !=, sal_False
                implCleanupItemEntry(*ppFnd1);
                implCleanupItemEntry(*GetPool(), *ppFnd1);
                // GetPool()->Remove( **ppFnd1 );
                *ppFnd1 = INVALID_POOL_ITEM;
            }
@@ -1159,7 +1341,7 @@ void SfxItemSet::MergeItem_Impl(const SfxPoolItem **ppFnd1, const SfxPoolItem *p
            {
                // Decision table: set, dontcare, doesn't matter, sal_False
                // or:             set, dontcare, !=, sal_True
                implCleanupItemEntry(*ppFnd1);
                implCleanupItemEntry(*GetPool(), *ppFnd1);
                // GetPool()->Remove( **ppFnd1 );
                *ppFnd1 = INVALID_POOL_ITEM;
            }
@@ -1170,7 +1352,7 @@ void SfxItemSet::MergeItem_Impl(const SfxPoolItem **ppFnd1, const SfxPoolItem *p
            if ( **ppFnd1 != *pFnd2 )
            {
                // Decision table: set, set, !=, doesn't matter
                implCleanupItemEntry(*ppFnd1);
                implCleanupItemEntry(*GetPool(), *ppFnd1);
                // GetPool()->Remove( **ppFnd1 );
                *ppFnd1 = INVALID_POOL_ITEM;
            }
@@ -1193,16 +1375,13 @@ void SfxItemSet::MergeValues( const SfxItemSet& rSet )
    //        evtl. could not find that WhichID in local WhichRanges
    // Better to loop over local WhichRanges (these get changed) and look
    // for Item with same WhichID in rSet, this is done now.

    const bool bSamePool(GetPool() == rSet.GetPool());

    if (GetRanges() == rSet.GetRanges())
    {

        // loop over both & merge, WhichIDs are identical
        for (const_iterator dst(begin()), src(rSet.begin()); dst != end(); dst++, src++)
        {
            MergeItem_Impl(dst, *src, bSamePool/*bItemIsSetMember*/, false/*bIgnoreDefaults*/);
            MergeItem_Impl(dst, *src, false/*bIgnoreDefaults*/);
        }
    }
    else
@@ -1220,7 +1399,7 @@ void SfxItemSet::MergeValues( const SfxItemSet& rSet )
                if (INVALID_WHICHPAIR_OFFSET != nOffset)
                {
                    // if entry with same WhichID exists in rSet, merge with local entry
                    MergeItem_Impl(dst, *(rSet.begin() + nOffset), bSamePool/*bItemIsSetMember*/, false/*bIgnoreDefaults*/);
                    MergeItem_Impl(dst, *(rSet.begin() + nOffset), false/*bIgnoreDefaults*/);
                }
            }
        }
@@ -1237,7 +1416,7 @@ void SfxItemSet::MergeValue(const SfxPoolItem& rAttr, bool bIgnoreDefaults)

    if (INVALID_WHICHPAIR_OFFSET != nOffset)
    {
        MergeItem_Impl(begin() + nOffset, &rAttr, false/*bItemIsSetMember*/, bIgnoreDefaults);
        MergeItem_Impl(begin() + nOffset, &rAttr, bIgnoreDefaults);
    }
}

@@ -1271,7 +1450,7 @@ void SfxItemSet::InvalidateItem_ForOffset(sal_uInt16 nOffset)
            return;

        // cleanup entry
        implCleanupItemEntry(*aFoundOne);
        implCleanupItemEntry(*GetPool(), *aFoundOne);
    }

    // set new entry
@@ -1329,14 +1508,11 @@ bool SfxItemSet::Equals(const SfxItemSet &rCmp, bool bComparePool) const
                  nWh;
                  nWh = aIter.NextWhich() )
            {
                // If the pointer of the poolable Items are unequal, the Items must match
                // If the pointer of the shareable Items are unequal, the Items must match
                const SfxPoolItem *pItem1 = nullptr, *pItem2 = nullptr;
                if ( GetItemState_ForWhichID(SfxItemState::UNKNOWN, nWh, false, &pItem1 ) !=
                        rCmp.GetItemState_ForWhichID(SfxItemState::UNKNOWN, nWh, false, &pItem2 ) ||
                     ( pItem1 != pItem2 &&
                        ( !pItem1 || IsInvalidItem(pItem1) ||
                          (GetPool()->IsItemPoolable(*pItem1) &&
                            *pItem1 != *pItem2 ) ) ) )
                        !SfxPoolItem::areSame(pItem1, pItem2))
                    return false;
            }

@@ -1353,13 +1529,9 @@ bool SfxItemSet::Equals(const SfxItemSet &rCmp, bool bComparePool) const
    const SfxPoolItem **ppItem2 = rCmp.m_ppItems;
    for ( sal_uInt16 nPos = 0; nPos < nCount1; ++nPos )
    {
        // If the pointers of the poolable Items are not the same, the Items
        // If the pointers of the shareable Items are not the same, the Items
        // must match
        if ( *ppItem1 != *ppItem2 &&
             ( ( !*ppItem1 || !*ppItem2 ) ||
               ( IsInvalidItem(*ppItem1) || IsInvalidItem(*ppItem2) ) ||
               (!bDifferentPools && GetPool()->IsItemPoolable(**ppItem1)) ||
                 **ppItem1 != **ppItem2 ) )
        if (!SfxPoolItem::areSame(*ppItem1, *ppItem2))
            return false;

        ++ppItem1;
@@ -1467,10 +1639,10 @@ SfxAllItemSet::SfxAllItemSet(const SfxAllItemSet &rCopy)
/**
 * Putting with automatic extension of the WhichId with the ID of the Item.
 */
const SfxPoolItem* SfxAllItemSet::PutImpl( const SfxPoolItem& rItem, sal_uInt16 nWhich, bool bItemIsSetMember, bool bPassingOwnership )
const SfxPoolItem* SfxAllItemSet::PutImpl( const SfxPoolItem& rItem, sal_uInt16 nWhich, bool bPassingOwnership )
{
    MergeRange(nWhich, nWhich);
    return SfxItemSet::PutImpl(rItem, nWhich, bItemIsSetMember, bPassingOwnership);
    return SfxItemSet::PutImpl(rItem, nWhich, bPassingOwnership);
}

/**
diff --git a/svl/source/items/poolcach.cxx b/svl/source/items/poolcach.cxx
index 882510c..957f9a3 100644
--- a/svl/source/items/poolcach.cxx
+++ b/svl/source/items/poolcach.cxx
@@ -28,7 +28,7 @@ SfxItemPoolCache::SfxItemPoolCache( SfxItemPool *pItemPool,
                                    const SfxPoolItem *pPutItem ):
    pPool(pItemPool),
    pSetToPut( nullptr ),
    pItemToPut( &pItemPool->Put(*pPutItem) )
    pItemToPut( &pItemPool->DirectPutItemInPool(*pPutItem) )
{
    DBG_ASSERT(pItemPool, "No Pool provided");
}
@@ -47,12 +47,12 @@ SfxItemPoolCache::SfxItemPoolCache( SfxItemPool *pItemPool,
SfxItemPoolCache::~SfxItemPoolCache()
{
    for (const SfxItemModifyImpl & rImpl : m_aCache) {
        pPool->Remove( *rImpl.pPoolItem );
        pPool->Remove( *rImpl.pOrigItem );
        pPool->DirectRemoveItemFromPool( *rImpl.pPoolItem );
        pPool->DirectRemoveItemFromPool( *rImpl.pOrigItem );
    }

    if ( pItemToPut )
        pPool->Remove( *pItemToPut );
        pPool->DirectRemoveItemFromPool( *pItemToPut );
}


@@ -65,13 +65,14 @@ const SfxSetItem& SfxItemPoolCache::ApplyTo( const SfxSetItem &rOrigItem )
    // Find whether this Transformations ever occurred
    for (const SfxItemModifyImpl & rMapEntry : m_aCache)
    {
        if ( rMapEntry.pOrigItem == &rOrigItem )
        // use Item PtrCompare OK
        if ( areSfxPoolItemPtrsEqual(rMapEntry.pOrigItem, &rOrigItem) )
        {
            // Did anything change at all?
            if ( rMapEntry.pPoolItem != &rOrigItem )
            // Did anything change at all? use Item PtrCompare OK
            if ( !areSfxPoolItemPtrsEqual(rMapEntry.pPoolItem, &rOrigItem) )
            {
                rMapEntry.pPoolItem->AddRef(2); // One for the cache
                pPool->Put( rOrigItem );    //FIXME: AddRef?
                pPool->DirectPutItemInPool( rOrigItem );    //FIXME: AddRef?
            }
            return *rMapEntry.pPoolItem;
        }
@@ -82,16 +83,16 @@ const SfxSetItem& SfxItemPoolCache::ApplyTo( const SfxSetItem &rOrigItem )
    if ( pItemToPut )
    {
        pNewItem->GetItemSet().Put( *pItemToPut );
        DBG_ASSERT( &pNewItem->GetItemSet().Get( pItemToPut->Which() ) == pItemToPut,
        DBG_ASSERT( areSfxPoolItemPtrsEqual(&pNewItem->GetItemSet().Get( pItemToPut->Which() ), pItemToPut),
                    "wrong item in temporary set" );
    }
    else
        pNewItem->GetItemSet().Put( *pSetToPut );
    const SfxSetItem* pNewPoolItem = &pPool->Put( std::move(pNewItem) );
    const SfxSetItem* pNewPoolItem = &pPool->DirectPutItemInPool( std::move(pNewItem) );

    // Adapt refcount; one each for the cache
    pNewPoolItem->AddRef( pNewPoolItem != &rOrigItem ? 2 : 1 );
    pPool->Put( rOrigItem );    //FIXME: AddRef?
    pNewPoolItem->AddRef( !areSfxPoolItemPtrsEqual(pNewPoolItem, &rOrigItem) ? 2 : 1 );
    pPool->DirectPutItemInPool( rOrigItem );    //FIXME: AddRef?

    // Add the transformation to the cache
    SfxItemModifyImpl aModify;
@@ -100,7 +101,7 @@ const SfxSetItem& SfxItemPoolCache::ApplyTo( const SfxSetItem &rOrigItem )
    m_aCache.push_back( aModify );

    DBG_ASSERT( !pItemToPut ||
                &pNewPoolItem->GetItemSet().Get( pItemToPut->Which() ) == pItemToPut,
                areSfxPoolItemPtrsEqual(&pNewPoolItem->GetItemSet().Get( pItemToPut->Which() ), pItemToPut),
                "wrong item in resulting set" );

    return *pNewPoolItem;
diff --git a/svl/source/items/poolitem.cxx b/svl/source/items/poolitem.cxx
index 928ac3d..94ce9ce 100644
--- a/svl/source/items/poolitem.cxx
+++ b/svl/source/items/poolitem.cxx
@@ -26,6 +26,10 @@
#include <typeinfo>
#include <boost/property_tree/ptree.hpp>

#ifdef DBG_UTIL
#include <unordered_set>
#endif

//////////////////////////////////////////////////////////////////////////////
// list of classes derived from SfxPoolItem
// will not be kept up-to-date, but give a good overview for right now
@@ -466,16 +470,32 @@ static size_t nAllocatedSfxPoolItemCount(0);
static size_t nUsedSfxPoolItemCount(0);
size_t getAllocatedSfxPoolItemCount() { return nAllocatedSfxPoolItemCount; }
size_t getUsedSfxPoolItemCount() { return nUsedSfxPoolItemCount; }
static std::unordered_set<const SfxPoolItem*> incarnatedSfxPoolItems;
void listAllocatedSfxPoolItems()
{
    SAL_INFO("svl.items", "ITEM: List of still allocated SfxPoolItems:");
    for (const auto& rCandidate : incarnatedSfxPoolItems)
    {
        SAL_INFO("svl.items", "  ITEM: WhichID: " << rCandidate->Which() << "  SerialNumber: "
                                                  << rCandidate->getSerialNumber()
                                                  << "  Class: " << typeid(*rCandidate).name());
    }
}
#endif

SfxPoolItem::SfxPoolItem(sal_uInt16 const nWhich)
    : m_nRefCount(0)
    , m_nWhich(nWhich)
#ifdef DBG_UTIL
    , m_nSerialNumber(nUsedSfxPoolItemCount)
#endif
    , m_bIsVoidItem(false)
    , m_bDeleteOnIdle(false)
    , m_bStaticDefault(false)
    , m_bPoolDefault(false)
    , m_bShareable(true)
    , m_bRegisteredAtPool(false)
    , m_bNewItemCallback(false)
    , m_bIsSetItem(false)
#ifdef DBG_UTIL
    , m_bDeleted(false)
#endif
@@ -483,6 +503,7 @@ SfxPoolItem::SfxPoolItem(sal_uInt16 const nWhich)
#ifdef DBG_UTIL
    nAllocatedSfxPoolItemCount++;
    nUsedSfxPoolItemCount++;
    incarnatedSfxPoolItems.insert(this);
#endif
    assert(nWhich <= SHRT_MAX);
}
@@ -491,6 +512,7 @@ SfxPoolItem::~SfxPoolItem()
{
#ifdef DBG_UTIL
    nAllocatedSfxPoolItemCount--;
    incarnatedSfxPoolItems.erase(this);
    m_bDeleted = true;
#endif
    assert((m_nRefCount == 0 || m_nRefCount > SFX_ITEMS_MAXREF) && "destroying item in use");
@@ -598,6 +620,70 @@ bool SfxPoolItem::PutValue(const css::uno::Any&, sal_uInt8)
    return false;
}

bool areSfxPoolItemPtrsEqual(const SfxPoolItem* pItem1, const SfxPoolItem* pItem2)
{
#ifdef DBG_UTIL
    if (nullptr != pItem1 && nullptr != pItem2 && pItem1->Which() == pItem2->Which()
        && static_cast<const void*>(pItem1) != static_cast<const void*>(pItem2)
        && typeid(*pItem1) == typeid(*pItem2) && *pItem1 == *pItem2)
    {
        SAL_INFO("svl.items", "ITEM: PtrCompare != ContentCompare (!)");
    }
#endif

    // cast to void* to not trigger [loplugin:itemcompare]
    return (static_cast<const void*>(pItem1) == static_cast<const void*>(pItem2));
}

bool SfxPoolItem::areSame(const SfxPoolItem* pItem1, const SfxPoolItem* pItem2)
{
    if (pItem1 == pItem2)
        // pointer compare, this handles already
        // nullptr, INVALID_POOL_ITEM, SfxVoidItem
        // and if any Item is indeed handed over twice
        return true;

    if (nullptr == pItem1 || nullptr == pItem2)
        // one ptr is nullptr, not both, that would
        // have triggered above
        return false;

    if (pItem1->Which() != pItem2->Which())
        // WhichIDs differ (fast)
        return false;

    if (typeid(*pItem1) != typeid(*pItem2))
        // types differ (fast)
        // NOTE: we can now use typeid since we do not have (-1)
        // anymore for Invalid state -> safe
        return false;

    // return content compare using operator== at last
    return *pItem1 == *pItem2;
}

bool SfxPoolItem::areSame(const SfxPoolItem& rItem1, const SfxPoolItem& rItem2)
{
    if (&rItem1 == &rItem2)
        // still use pointer compare, this handles already
        // nullptr, INVALID_POOL_ITEM, SfxVoidItem
        // and if any Item is indeed handed over twice
        return true;

    if (rItem1.Which() != rItem2.Which())
        // WhichIDs differ (fast)
        return false;

    if (typeid(rItem1) != typeid(rItem2))
        // types differ (fast)
        // NOTE: we can now use typeid since we do not have (-1)
        // anymore for Invalid state -> safe
        return false;

    // return content compare using operator== at last
    return rItem1 == rItem2;
}

namespace
{
class InvalidItem final : public SfxPoolItem
diff --git a/svl/source/items/sitem.cxx b/svl/source/items/sitem.cxx
index a34b9eb..037097f 100644
--- a/svl/source/items/sitem.cxx
+++ b/svl/source/items/sitem.cxx
@@ -29,6 +29,7 @@ SfxSetItem::SfxSetItem( sal_uInt16 which, const SfxItemSet &rSet) :
    maSet(rSet)
{
    assert(!dynamic_cast<const SfxAllItemSet*>(&rSet) && "cannot handle SfxAllItemSet here");
    setIsSetItem();
}


@@ -37,6 +38,7 @@ SfxSetItem::SfxSetItem( sal_uInt16 which, SfxItemSet &&pS) :
    maSet(pS)
{
    assert(!dynamic_cast<SfxAllItemSet*>(&pS) && "cannot handle SfxAllItemSet here");
    setIsSetItem();
}


@@ -45,6 +47,7 @@ SfxSetItem::SfxSetItem( const SfxSetItem& rCopy, SfxItemPool *pPool ) :
    maSet(rCopy.maSet.CloneAsValue(true, pPool))
{
    assert(!dynamic_cast<const SfxAllItemSet*>(&rCopy.maSet) && "cannot handle SfxAllItemSet here");
    setIsSetItem();
}


diff --git a/svl/source/items/stylepool.cxx b/svl/source/items/stylepool.cxx
index dc992a6..9de8d87 100644
--- a/svl/source/items/stylepool.cxx
+++ b/svl/source/items/stylepool.cxx
@@ -373,7 +373,7 @@ public:

std::shared_ptr<SfxItemSet> StylePoolImpl::insertItemSet( const SfxItemSet& rSet, const OUString* pParentName )
{
    bool bNonPoolable = false;
    bool bNonShareable(false);
    Node* pCurNode = &maRoot[ rSet.GetParent() ];
    if (pParentName)
        maParentNames[ rSet.GetParent() ] = *pParentName;
@@ -389,8 +389,8 @@ std::shared_ptr<SfxItemSet> StylePoolImpl::insertItemSet( const SfxItemSet& rSet
    }
    while( pItem )
    {
        if( !rSet.GetPool()->IsItemPoolable(pItem->Which() ) )
            bNonPoolable = true;
        if (!rSet.GetPool()->Shareable(pItem->Which()))
            bNonShareable = true;
        if (!xFoundIgnorableItems || (xFoundIgnorableItems->Put(*pItem) == nullptr))
        {
            pCurNode = pCurNode->findChildNode( *pItem, false );
@@ -403,8 +403,8 @@ std::shared_ptr<SfxItemSet> StylePoolImpl::insertItemSet( const SfxItemSet& rSet
        pItem = aIgnorableItemsIter.GetCurItem();
        while( pItem )
        {
            if( !rSet.GetPool()->IsItemPoolable(pItem->Which() ) )
                bNonPoolable = true;
            if (!rSet.GetPool()->Shareable(pItem->Which()))
                bNonShareable = true;
            pCurNode = pCurNode->findChildNode( *pItem, true );
            pItem = aIgnorableItemsIter.NextItem();
        }
@@ -415,13 +415,13 @@ std::shared_ptr<SfxItemSet> StylePoolImpl::insertItemSet( const SfxItemSet& rSet
    if( !pCurNode->hasItemSet( false ) )
    {
        pCurNode->setItemSet( rSet );
        bNonPoolable = false; // to avoid a double insertion
        bNonShareable = false; // to avoid a double insertion
#ifdef DEBUG
        ++mnCount;
#endif
    }
    // If rSet contains at least one non poolable item, a new itemset has to be inserted
    if( bNonPoolable )
    if( bNonShareable )
        pCurNode->setItemSet( rSet );
#ifdef DEBUG
    {
diff --git a/svl/source/items/voiditem.cxx b/svl/source/items/voiditem.cxx
index 6977c28..32057e1e 100644
--- a/svl/source/items/voiditem.cxx
+++ b/svl/source/items/voiditem.cxx
@@ -25,19 +25,19 @@ SfxPoolItem* SfxVoidItem::CreateDefault() { return new SfxVoidItem(0); }
SfxVoidItem::SfxVoidItem(sal_uInt16 which)
    : SfxPoolItem(which)
{
    setVoidItem();
    setIsVoidItem();
}

SfxVoidItem::SfxVoidItem(const SfxVoidItem& rCopy)
    : SfxPoolItem(rCopy.Which())
{
    setVoidItem();
    setIsVoidItem();
}

SfxVoidItem::SfxVoidItem(SfxVoidItem&& rOrig)
    : SfxPoolItem(rOrig)
{
    setVoidItem();
    setIsVoidItem();
}

bool SfxVoidItem::operator==(const SfxPoolItem& rCmp) const
diff --git a/svx/qa/unit/customshapes.cxx b/svx/qa/unit/customshapes.cxx
index be3808d..523cf73 100644
--- a/svx/qa/unit/customshapes.cxx
+++ b/svx/qa/unit/customshapes.cxx
@@ -150,7 +150,7 @@ CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf147409_GeomItemHash)
    pSdrView->MarkObj(pSdrCustomShape, pSdrView->GetSdrPageView());

    // Apply FontworkSameLetterHeights toggle
    // Without patch a debug build fails assert in SfxItemPool::PutImpl and so crashes.
    // Without patch a debug build fails assert in SfxItemPool::DirectPutItemInPoolImpl and so crashes.
    dispatchCommand(mxComponent, ".uno:FontworkSameLetterHeights", {});
}

@@ -167,7 +167,7 @@ CPPUNIT_TEST_FIXTURE(CustomshapesTest, testTdf146866_GeomItemHash)
    pSdrView->MarkObj(pSdrCustomShape, pSdrView->GetSdrPageView());

    // Apply extrusion toggle
    // Without patch a debug build fails assert in SfxItemPool::PutImpl and so crashes.
    // Without patch a debug build fails assert in SfxItemPool::DirectPutItemInPoolImpl and so crashes.
    dispatchCommand(mxComponent, ".uno:ExtrusionToggle", {});
}

diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx
index 24c69fb..c5efc9f 100644
--- a/svx/source/dialog/framelinkarray.cxx
+++ b/svx/source/dialog/framelinkarray.cxx
@@ -269,11 +269,11 @@ static void lclSetMergedRange( SfxItemPool& rPool, CellVec& rCells, sal_Int32 nW
            Cell aTempCell(*pCell);
            aTempCell.mbOverlapX = nCol > nFirstCol;
            aTempCell.mbOverlapY = nRow > nFirstRow;
            rCells[ nRow * nWidth + nCol ] = &rPool.Put(aTempCell);
            rCells[ nRow * nWidth + nCol ] = &rPool.DirectPutItemInPool(aTempCell);
        }
    }
    Cell aTempCell(*rCells[ nFirstRow * nWidth + nFirstCol ]);
    rCells[ nFirstRow * nWidth + nFirstCol ] = &rPool.Put(aTempCell);
    rCells[ nFirstRow * nWidth + nFirstCol ] = &rPool.DirectPutItemInPool(aTempCell);
}


@@ -336,8 +336,10 @@ struct ArrayImpl
    bool                HasCellRotation() const;
};

const SfxItemInfo maItemInfos[] {
    {0, true}
const SfxItemInfo maItemInfos[]
{
    // _nSID, _bNeedsPoolRegistration, _bShareable
    {0, false, true }
};
ArrayImpl::ArrayImpl( sal_Int32 nWidth, sal_Int32 nHeight ) :
    mxPool(new SfxItemPool("Mine", 10, 10, maItemInfos)),
@@ -351,7 +353,7 @@ ArrayImpl::ArrayImpl( sal_Int32 nWidth, sal_Int32 nHeight ) :
    mbYCoordsDirty( false ),
    mbMayHaveCellRotation( false )
{
    const Cell* pDefaultCell = &mxPool->Put(Cell());
    const Cell* pDefaultCell = &mxPool->DirectPutItemInPool(Cell());
    // default-construct all vectors
    maCells.resize( mnWidth * mnHeight, pDefaultCell );
    maWidths.resize( mnWidth, 0 );
@@ -368,7 +370,7 @@ const Cell& ArrayImpl::GetCell( sal_Int32 nCol, sal_Int32 nRow ) const
void ArrayImpl::PutCell( sal_Int32 nCol, sal_Int32 nRow, const Cell & rCell )
{
    if (IsValidPos( nCol, nRow ))
        maCells[ GetIndex( nCol, nRow ) ] = &mxPool->Put(rCell);
        maCells[ GetIndex( nCol, nRow ) ] = &mxPool->DirectPutItemInPool(rCell);
}

sal_Int32 ArrayImpl::GetMergedFirstCol( sal_Int32 nCol, sal_Int32 nRow ) const
@@ -1061,7 +1063,7 @@ void Array::MirrorSelfX()
        {
            Cell aTempCell(CELL(mxImpl->GetMirrorCol( nCol ), nRow));
            aTempCell.MirrorSelfX();
            aNewCells.push_back( &mxImpl->mxPool->Put(aTempCell) );
            aNewCells.push_back( &mxImpl->mxPool->DirectPutItemInPool(aTempCell) );
        }
    }
    mxImpl->maCells.swap( aNewCells );
diff --git a/svx/source/items/customshapeitem.cxx b/svx/source/items/customshapeitem.cxx
index 1aaa0e7..7fc4a06 100644
--- a/svx/source/items/customshapeitem.cxx
+++ b/svx/source/items/customshapeitem.cxx
@@ -239,23 +239,6 @@ bool SdrCustomShapeGeometryItem::operator==( const SfxPoolItem& rCmp ) const
    return m_aPropSeq == other.m_aPropSeq;
}

bool SdrCustomShapeGeometryItem::operator<( const SfxPoolItem& rCmp ) const
{
    assert(dynamic_cast<const SdrCustomShapeGeometryItem*>( &rCmp ));
    const SdrCustomShapeGeometryItem& other = static_cast<const SdrCustomShapeGeometryItem&>(rCmp);
    // Again, try to optimize by checking hashes first (this is operator< for sorting purposes,
    // so the ordering can be somewhat arbitrary).
    UpdateHash();
    other.UpdateHash();
    if( m_aHashState != other.m_aHashState )
        return m_aHashState < other.m_aHashState;
    if( m_aHashState == HashState::Valid )
        return m_aHash < other.m_aHash;

    return comphelper::anyLess( css::uno::Any( m_aPropSeq ),
        css::uno::Any( other.m_aPropSeq ));
}

void SdrCustomShapeGeometryItem::UpdateHash() const
{
    if( m_aHashState != HashState::Unknown )
diff --git a/svx/source/items/pageitem.cxx b/svx/source/items/pageitem.cxx
index 93239ea..65e016f 100644
--- a/svx/source/items/pageitem.cxx
+++ b/svx/source/items/pageitem.cxx
@@ -256,9 +256,9 @@ SvxSetItem::SvxSetItem( const TypedWhichId<SvxSetItem> nId, const SfxItemSet& rS
{
}

SvxSetItem::SvxSetItem( const SvxSetItem& rItem ) :
SvxSetItem::SvxSetItem( const SvxSetItem& rItem, SfxItemPool* pPool ) :

    SfxSetItem( rItem )
    SfxSetItem( rItem, pPool )
{
}

@@ -268,9 +268,9 @@ SvxSetItem::SvxSetItem( const TypedWhichId<SvxSetItem> nId, SfxItemSet&& _pSet )
{
}

SvxSetItem* SvxSetItem::Clone( SfxItemPool * ) const
SvxSetItem* SvxSetItem::Clone( SfxItemPool * pPool ) const
{
    return new SvxSetItem(*this);
    return new SvxSetItem(*this, pPool);
}

bool SvxSetItem::GetPresentation
diff --git a/svx/source/sidebar/nbdtmg.cxx b/svx/source/sidebar/nbdtmg.cxx
index ebdfa34..b572d49 100644
--- a/svx/source/sidebar/nbdtmg.cxx
+++ b/svx/source/sidebar/nbdtmg.cxx
@@ -666,7 +666,7 @@ sal_uInt16 OutlineTypeMgr::GetNBOIndexForNumRule(SvxNumRule& aNum,sal_uInt16 /*m
                const SvxBrushItem* pBrsh1 = aFmt.GetBrush();
                const SvxBrushItem* pBrsh2 = _pSet->pBrushItem;
                bool bIsMatch = false;
                if (pBrsh1==pBrsh2) bIsMatch = true;
                if (SfxPoolItem::areSame(pBrsh1,pBrsh2)) bIsMatch = true;
                if (pBrsh1 && pBrsh2) {
                    const Graphic* pGrf1 = pBrsh1->GetGraphic();
                    const Graphic* pGrf2 = pBrsh2->GetGraphic();
diff --git a/svx/source/svdraw/svdattr.cxx b/svx/source/svdraw/svdattr.cxx
index 0a4ce01..6ba680e 100644
--- a/svx/source/svdraw/svdattr.cxx
+++ b/svx/source/svdraw/svdattr.cxx
@@ -126,9 +126,13 @@ SdrItemPool::SdrItemPool(
    // init the non-persistent items
    for(sal_uInt16 i(SDRATTR_NOTPERSIST_FIRST); i <= SDRATTR_NOTPERSIST_LAST; i++)
    {
        mpLocalItemInfos[i - SDRATTR_START]._bPoolable = false;
        mpLocalItemInfos[i - SDRATTR_START]._bNeedsPoolRegistration = false;
    }

    // these slots need _bNeedsPoolRegistration == true, see
    // text @svl/source/items/itempool.cxx
    mpLocalItemInfos[SDRATTR_XMLATTRIBUTES -SDRATTR_START]._bNeedsPoolRegistration = true;

    // init own PoolDefaults
    std::vector<SfxPoolItem*>& rPoolDefaults = *mpLocalPoolDefaults;
    rPoolDefaults[SDRATTR_SHADOW            -SDRATTR_START]=new SdrOnOffItem(SDRATTR_SHADOW, false);
diff --git a/svx/source/unodraw/UnoNamespaceMap.cxx b/svx/source/unodraw/UnoNamespaceMap.cxx
index 0eced85..b013c5a 100644
--- a/svx/source/unodraw/UnoNamespaceMap.cxx
+++ b/svx/source/unodraw/UnoNamespaceMap.cxx
@@ -127,8 +127,9 @@ NamespaceIteratorImpl::NamespaceIteratorImpl( sal_uInt16* pWhichIds, SfxItemPool
    mnItem = -1;
    if (mpWhichId && (0 != *mpWhichId) && mpPool)
    {
        mvItems.reserve(mpPool->GetItemCount2( *mpWhichId ));
        for (const SfxPoolItem* pItem : mpPool->GetItemSurrogates( *mpWhichId ))
        const registeredSfxPoolItems& rSurrogates(mpPool->GetItemSurrogates(*mpWhichId));
        mvItems.reserve(rSurrogates.size());
        for (const SfxPoolItem* pItem : rSurrogates)
            mvItems.push_back(static_cast<const SvXMLAttrContainerItem*>(pItem));
    }
}
@@ -162,8 +163,9 @@ bool NamespaceIteratorImpl::next( OUString& rPrefix, OUString& rURL )
        mvItems.clear();
        if (mpPool)
        {
            mvItems.reserve(mpPool->GetItemCount2( *mpWhichId ));
            for (const SfxPoolItem* pItem2 : mpPool->GetItemSurrogates( *mpWhichId ))
            const registeredSfxPoolItems& rSurrogates(mpPool->GetItemSurrogates(*mpWhichId));
            mvItems.reserve(rSurrogates.size());
            for (const SfxPoolItem* pItem2 : rSurrogates)
                mvItems.push_back(static_cast<const SvXMLAttrContainerItem*>(pItem2));
        }
        return next( rPrefix, rURL );
diff --git a/svx/source/xoutdev/xpool.cxx b/svx/source/xoutdev/xpool.cxx
index e0a2807..0174019 100644
--- a/svx/source/xoutdev/xpool.cxx
+++ b/svx/source/xoutdev/xpool.cxx
@@ -159,10 +159,24 @@ XOutdevItemPool::XOutdevItemPool(SfxItemPool* _pMaster)
    // create ItemInfos
    for(sal_uInt16 i(GetFirstWhich()); i <= GetLastWhich(); i++)
    {
        // _nSID, _bNeedsPoolRegistration, _bShareable
        mpLocalItemInfos[i - XATTR_START]._nSID = 0;
        mpLocalItemInfos[i - XATTR_START]._bPoolable = true;
        mpLocalItemInfos[i - XATTR_START]._bNeedsPoolRegistration = false;
        mpLocalItemInfos[i - XATTR_START]._bShareable = true;
    }

    // these slots need _bNeedsPoolRegistration == true, see
    // text @svl/source/items/itempool.cxx
    mpLocalItemInfos[XATTR_FILLBITMAP       -XATTR_START]._bNeedsPoolRegistration = true;
    mpLocalItemInfos[XATTR_FILLGRADIENT     -XATTR_START]._bNeedsPoolRegistration = true;
    mpLocalItemInfos[XATTR_FILLHATCH        -XATTR_START]._bNeedsPoolRegistration = true;
    mpLocalItemInfos[XATTR_FILLFLOATTRANSPARENCE - XATTR_START]._bNeedsPoolRegistration = true;
    mpLocalItemInfos[XATTR_LINEEND          -XATTR_START]._bNeedsPoolRegistration = true;
    mpLocalItemInfos[XATTR_LINESTART        -XATTR_START]._bNeedsPoolRegistration = true;
    mpLocalItemInfos[XATTR_LINEDASH         -XATTR_START]._bNeedsPoolRegistration = true;
    mpLocalItemInfos[XATTR_FILLCOLOR        -XATTR_START]._bNeedsPoolRegistration = true;

    // set the SlotIDs, this is a mapping used by GetWhich()/GetSlotId()
    mpLocalItemInfos[XATTR_LINESTYLE        -XATTR_START]._nSID = SID_ATTR_LINE_STYLE;
    mpLocalItemInfos[XATTR_LINEDASH         -XATTR_START]._nSID = SID_ATTR_LINE_DASH;
    mpLocalItemInfos[XATTR_LINEWIDTH        -XATTR_START]._nSID = SID_ATTR_LINE_WIDTH;
diff --git a/sw/source/core/attr/cellatr.cxx b/sw/source/core/attr/cellatr.cxx
index 09b070e..9023cca 100644
--- a/sw/source/core/attr/cellatr.cxx
+++ b/sw/source/core/attr/cellatr.cxx
@@ -58,9 +58,6 @@ SwTableBoxFormula::SwTableBoxFormula( const OUString& rFormula )
    SwTableFormula( rFormula ),
    m_pDefinedIn( nullptr )
{
    // ITEM: mark this Item to be non-shareable/non-RefCountable. For more
    // info see comment @SwAttrSet::SetModifyAtAttr
    m_bShareable = false;
}

bool SwTableBoxFormula::operator==( const SfxPoolItem& rAttr ) const
diff --git a/sw/source/core/attr/hints.cxx b/sw/source/core/attr/hints.cxx
index 7102ce7..641d738 100644
--- a/sw/source/core/attr/hints.cxx
+++ b/sw/source/core/attr/hints.cxx
@@ -140,10 +140,13 @@ SwMsgPoolItem::SwMsgPoolItem( sal_uInt16 nWhch )
{
}

bool SwMsgPoolItem::operator==( const SfxPoolItem& ) const
bool SwMsgPoolItem::operator==( const SfxPoolItem& rItem ) const
{
    assert( false && "SwMsgPoolItem knows no ==" );
    return false;
    assert( SfxPoolItem::operator==(rItem)); (void)rItem;
    // SwMsgPoolItem now knows operator== due to evtl. deeper
    // ItemCompares using SfxPoolItem::areSame. No members,
    // so always equal
    return true;
}

SwMsgPoolItem* SwMsgPoolItem::Clone( SfxItemPool* ) const
diff --git a/sw/source/core/attr/swatrset.cxx b/sw/source/core/attr/swatrset.cxx
index b08026a..fc46127 100644
--- a/sw/source/core/attr/swatrset.cxx
+++ b/sw/source/core/attr/swatrset.cxx
@@ -141,12 +141,12 @@ void SwAttrSet::changeCallback(const SfxPoolItem* pOld, const SfxPoolItem* pNew)
            const SfxItemSet* pParent(GetParent());
            m_pOldSet->PutImpl(nullptr != pParent
                ? pParent->Get(nWhich)
                : GetPool()->GetDefaultItem(nWhich), nWhich, false, false);
                : GetPool()->GetDefaultItem(nWhich), nWhich, false);
        }
        else if (!IsInvalidItem(pOld))
        {
            // set/remember old value
            m_pOldSet->PutImpl(*pOld, nWhich, true, false);
            m_pOldSet->PutImpl(*pOld, nWhich, false);
        }
    }

@@ -159,12 +159,12 @@ void SwAttrSet::changeCallback(const SfxPoolItem* pOld, const SfxPoolItem* pNew)
            const SfxItemSet* pParent(GetParent());
            m_pNewSet->PutImpl(nullptr != pParent
                ? pParent->Get(nWhich)
                : GetPool()->GetDefaultItem(nWhich), nWhich, false, false);
                : GetPool()->GetDefaultItem(nWhich), nWhich, false);
        }
        else if (!IsInvalidItem(pNew))
        {
            // set/remember new value
            m_pNewSet->PutImpl(*pNew, nWhich, true, false);
            m_pNewSet->PutImpl(*pNew, nWhich, false);
        }
    }
}
@@ -337,33 +337,6 @@ bool SwAttrSet::SetModifyAtAttr( const sw::BroadcastingModify* pModify )
{
    bool bSet = false;

    // ITEM: At this place the paradigm of Item/Set/Pool gets broken:
    // The three Items in Writer
    // - SwFormatPageDesc
    // - SwFormatDrop
    // - SwTableBoxFormula
    // contain a unique ptr to SwFormat (or: sw::BroadcastingModify
    // if you wish), so the Item *cannot* be shared or re-used.
    // But that is the intended nature of Items:
    // - they are read-only (note the bad const_cast's below)
    // - they are ref-counted to be re-usable in as many Sets as
    //   possible
    // Thus if we need to change that ptr @ Item we *need* to make
    // sure that Item is *unique*. This is now done by using the
    // 'm_bShareable' at the Item (see where that gets set).
    // This was done in the past using the 'poolable' flag, but that
    // flag was/is for a completely different purpose - uniqueness is
    // a side-effect. It already led to massively cloning that Item.
    // That something is not 'clean' here can also be seen by using
    // const_cast to *change* values at Items *in* the Set - these
    // are returned by const reference for a purpose.
    // If info/data at an Item has to be changed, the official/clean
    // way is to create a new one (e.g. Clone), set the values (if
    // not given to the constructor) and then set that Item at the Set.
    // NOTE: I do not know if and how it would be possible, but holding
    //       a SwFormat*/sw::BroadcastingModify* at those Items should
    //       be fixed/removed ASAP

    const SwFormatPageDesc* pPageDescItem = GetItemIfSet( RES_PAGEDESC, false );
    if( pPageDescItem &&
        pPageDescItem->GetDefinedIn() != pModify  )
diff --git a/sw/source/core/bastyp/init.cxx b/sw/source/core/bastyp/init.cxx
index 3e286b3..f008071 100644
--- a/sw/source/core/bastyp/init.cxx
+++ b/sw/source/core/bastyp/init.cxx
@@ -264,180 +264,181 @@ SwDfltAttrTab aAttrTab( POOLATTR_END - POOLATTR_BEGIN, nullptr );

SfxItemInfo aSlotTab[] =
{
    { SID_ATTR_CHAR_CASEMAP, true },       // RES_CHRATR_CASEMAP
    { SID_ATTR_CHAR_CHARSETCOLOR, true },  // RES_CHRATR_CHARSETCOLOR
    { SID_ATTR_CHAR_COLOR, true },         // RES_CHRATR_COLOR
    { SID_ATTR_CHAR_CONTOUR, true },       // RES_CHRATR_CONTOUR
    { SID_ATTR_CHAR_STRIKEOUT, true },     // RES_CHRATR_CROSSEDOUT
    { SID_ATTR_CHAR_ESCAPEMENT, true },    // RES_CHRATR_ESCAPEMENT
    { SID_ATTR_CHAR_FONT, true },          // RES_CHRATR_FONT
    { SID_ATTR_CHAR_FONTHEIGHT, true },    // RES_CHRATR_FONTSIZE
    { SID_ATTR_CHAR_KERNING, true },       // RES_CHRATR_KERNING
    { SID_ATTR_CHAR_LANGUAGE, true },      // RES_CHRATR_LANGUAGE
    { SID_ATTR_CHAR_POSTURE, true },       // RES_CHRATR_POSTURE
    { 0, true },                           // RES_CHRATR_UNUSED1
    { SID_ATTR_CHAR_SHADOWED, true },      // RES_CHRATR_SHADOWED
    { SID_ATTR_CHAR_UNDERLINE, true },     // RES_CHRATR_UNDERLINE
    { SID_ATTR_CHAR_WEIGHT, true },        // RES_CHRATR_WEIGHT
    { SID_ATTR_CHAR_WORDLINEMODE, true },  // RES_CHRATR_WORDLINEMODE
    { SID_ATTR_CHAR_AUTOKERN, true },      // RES_CHRATR_AUTOKERN
    { SID_ATTR_FLASH, true },              // RES_CHRATR_BLINK
    { 0, true },                           // RES_CHRATR_UNUSED2
    { 0, true },                           // RES_CHRATR_NOHYPHEN
    { SID_ATTR_BRUSH_CHAR, true },         // RES_CHRATR_BACKGROUND
    { SID_ATTR_CHAR_CJK_FONT, true },      // RES_CHRATR_CJK_FONT
    { SID_ATTR_CHAR_CJK_FONTHEIGHT, true },// RES_CHRATR_CJK_FONTSIZE
    { SID_ATTR_CHAR_CJK_LANGUAGE, true },  // RES_CHRATR_CJK_LANGUAGE
    { SID_ATTR_CHAR_CJK_POSTURE, true },   // RES_CHRATR_CJK_POSTURE
    { SID_ATTR_CHAR_CJK_WEIGHT, true },    // RES_CHRATR_CJK_WEIGHT
    { SID_ATTR_CHAR_CTL_FONT, true },      // RES_CHRATR_CTL_FONT
    { SID_ATTR_CHAR_CTL_FONTHEIGHT, true },// RES_CHRATR_CTL_FONTSIZE
    { SID_ATTR_CHAR_CTL_LANGUAGE, true },  // RES_CHRATR_CTL_LANGUAGE
    { SID_ATTR_CHAR_CTL_POSTURE, true },   // RES_CHRATR_CTL_POSTURE
    { SID_ATTR_CHAR_CTL_WEIGHT, true },    // RES_CHRATR_CTL_WEIGHT
    { SID_ATTR_CHAR_ROTATED, true },       // RES_CHRATR_ROTATE
    { SID_ATTR_CHAR_EMPHASISMARK, true },  // RES_CHRATR_EMPHASIS_MARK
    { SID_ATTR_CHAR_TWO_LINES, true },     // RES_CHRATR_TWO_LINES
    { SID_ATTR_CHAR_SCALEWIDTH, true },    // RES_CHRATR_SCALEW
    { SID_ATTR_CHAR_RELIEF, true },        // RES_CHRATR_RELIEF
    { SID_ATTR_CHAR_HIDDEN, true },        // RES_CHRATR_HIDDEN
    { SID_ATTR_CHAR_OVERLINE, true },      // RES_CHRATR_OVERLINE
    { 0, true },                           // RES_CHRATR_RSID
    { SID_ATTR_CHAR_BOX, true },           // RES_CHRATR_BOX
    { SID_ATTR_CHAR_SHADOW, true },        // RES_CHRATR_SHADOW
    { 0, true },                           // RES_CHRATR_HIGHLIGHT
    { SID_ATTR_CHAR_GRABBAG, true },       // RES_CHRATR_GRABBAG
    { 0, true },                           // RES_CHRATR_BIDIRTL
    { 0, true },                           // RES_CHRATR_IDCTHINT
    // _nSID, _bNeedsPoolRegistration, _bShareable
    { SID_ATTR_CHAR_CASEMAP,            false, true },  // RES_CHRATR_CASEMAP
    { SID_ATTR_CHAR_CHARSETCOLOR,       false, true },  // RES_CHRATR_CHARSETCOLOR
    { SID_ATTR_CHAR_COLOR,              true,  true },  // RES_CHRATR_COLOR
    { SID_ATTR_CHAR_CONTOUR,            false, true },  // RES_CHRATR_CONTOUR
    { SID_ATTR_CHAR_STRIKEOUT,          false, true },  // RES_CHRATR_CROSSEDOUT
    { SID_ATTR_CHAR_ESCAPEMENT,         false, true },  // RES_CHRATR_ESCAPEMENT
    { SID_ATTR_CHAR_FONT,               true,  true },  // RES_CHRATR_FONT
    { SID_ATTR_CHAR_FONTHEIGHT,         false, true },  // RES_CHRATR_FONTSIZE
    { SID_ATTR_CHAR_KERNING,            false, true },  // RES_CHRATR_KERNING
    { SID_ATTR_CHAR_LANGUAGE,           false, true },  // RES_CHRATR_LANGUAGE
    { SID_ATTR_CHAR_POSTURE,            false, true },  // RES_CHRATR_POSTURE
    { 0,                                false, true },  // RES_CHRATR_UNUSED1
    { SID_ATTR_CHAR_SHADOWED,           false, true },  // RES_CHRATR_SHADOWED
    { SID_ATTR_CHAR_UNDERLINE,          true,  true },  // RES_CHRATR_UNDERLINE
    { SID_ATTR_CHAR_WEIGHT,             false, true },  // RES_CHRATR_WEIGHT
    { SID_ATTR_CHAR_WORDLINEMODE,       false, true },  // RES_CHRATR_WORDLINEMODE
    { SID_ATTR_CHAR_AUTOKERN,           false, true },  // RES_CHRATR_AUTOKERN
    { SID_ATTR_FLASH,                   false, true },  // RES_CHRATR_BLINK
    { 0,                                false, true },  // RES_CHRATR_UNUSED2
    { 0,                                false, true },  // RES_CHRATR_NOHYPHEN
    { SID_ATTR_BRUSH_CHAR,              true,  true },  // RES_CHRATR_BACKGROUND
    { SID_ATTR_CHAR_CJK_FONT,           true,  true },  // RES_CHRATR_CJK_FONT
    { SID_ATTR_CHAR_CJK_FONTHEIGHT,     false, true },  // RES_CHRATR_CJK_FONTSIZE
    { SID_ATTR_CHAR_CJK_LANGUAGE,       false, true },  // RES_CHRATR_CJK_LANGUAGE
    { SID_ATTR_CHAR_CJK_POSTURE,        false, true },  // RES_CHRATR_CJK_POSTURE
    { SID_ATTR_CHAR_CJK_WEIGHT,         false, true },  // RES_CHRATR_CJK_WEIGHT
    { SID_ATTR_CHAR_CTL_FONT,           true,  true },  // RES_CHRATR_CTL_FONT
    { SID_ATTR_CHAR_CTL_FONTHEIGHT,     false, true },  // RES_CHRATR_CTL_FONTSIZE
    { SID_ATTR_CHAR_CTL_LANGUAGE,       false, true },  // RES_CHRATR_CTL_LANGUAGE
    { SID_ATTR_CHAR_CTL_POSTURE,        false, true },  // RES_CHRATR_CTL_POSTURE
    { SID_ATTR_CHAR_CTL_WEIGHT,         false, true },  // RES_CHRATR_CTL_WEIGHT
    { SID_ATTR_CHAR_ROTATED,            false, true },  // RES_CHRATR_ROTATE
    { SID_ATTR_CHAR_EMPHASISMARK,       false, true },  // RES_CHRATR_EMPHASIS_MARK
    { SID_ATTR_CHAR_TWO_LINES,          false, true },  // RES_CHRATR_TWO_LINES
    { SID_ATTR_CHAR_SCALEWIDTH,         false, true },  // RES_CHRATR_SCALEW
    { SID_ATTR_CHAR_RELIEF,             false, true },  // RES_CHRATR_RELIEF
    { SID_ATTR_CHAR_HIDDEN,             false, true },  // RES_CHRATR_HIDDEN
    { SID_ATTR_CHAR_OVERLINE,           true,  true },  // RES_CHRATR_OVERLINE
    { 0,                                false, true },  // RES_CHRATR_RSID
    { SID_ATTR_CHAR_BOX,                true,  true },  // RES_CHRATR_BOX
    { SID_ATTR_CHAR_SHADOW,             false, true },  // RES_CHRATR_SHADOW
    { 0,                                true,  true },  // RES_CHRATR_HIGHLIGHT
    { SID_ATTR_CHAR_GRABBAG,            false, true },  // RES_CHRATR_GRABBAG
    { 0,                                false, true },  // RES_CHRATR_BIDIRTL
    { 0,                                false, true },  // RES_CHRATR_IDCTHINT

    { 0, false },                               // RES_TXTATR_REFMARK
    { 0, false },                               // RES_TXTATR_TOXMARK
    { 0, false },                               // RES_TXTATR_META
    { 0, false },                               // RES_TXTATR_METAFIELD
    { 0, true },                           // RES_TXTATR_AUTOFMT
    { FN_TXTATR_INET, false },                  // RES_TXTATR_INETFMT
    { 0, false },                               // RES_TXTATR_CHARFMT
    { SID_ATTR_CHAR_CJK_RUBY, false },          // RES_TXTATR_CJK_RUBY
    { 0, true },                           // RES_TXTATR_UNKNOWN_CONTAINER
    { 0, false },                               // RES_TXTATR_INPUTFIELD
    { 0, false },                               // RES_TXTATR_CONTENTCONTROL
    { 0,                                true,  false }, // RES_TXTATR_REFMARK
    { 0,                                true,  false }, // RES_TXTATR_TOXMARK
    { 0,                                false, false }, // RES_TXTATR_META
    { 0,                                false, false }, // RES_TXTATR_METAFIELD
    { 0,                                false, true },  // RES_TXTATR_AUTOFMT
    { FN_TXTATR_INET,                   true,  false }, // RES_TXTATR_INETFMT
    { 0,                                false, false }, // RES_TXTATR_CHARFMT
    { SID_ATTR_CHAR_CJK_RUBY,           true,  false }, // RES_TXTATR_CJK_RUBY
    { 0,                                true,  true },  // RES_TXTATR_UNKNOWN_CONTAINER
    { 0,                                true,  false }, // RES_TXTATR_INPUTFIELD
    { 0,                                false, false }, // RES_TXTATR_CONTENTCONTROL

    { 0, false },                               // RES_TXTATR_FIELD
    { 0, false },                               // RES_TXTATR_FLYCNT
    { 0, false },                               // RES_TXTATR_FTN
    { 0, false },                               // RES_TXTATR_ANNOTATION
    { 0, false },                               // RES_TXTATR_LINEBREAK
    { 0, true },                           // RES_TXTATR_DUMMY1
    { 0,                                true,  false }, // RES_TXTATR_FIELD
    { 0,                                false, false }, // RES_TXTATR_FLYCNT
    { 0,                                false, false }, // RES_TXTATR_FTN
    { 0,                                false, false }, // RES_TXTATR_ANNOTATION
    { 0,                                false, false }, // RES_TXTATR_LINEBREAK
    { 0,                                false, true },  // RES_TXTATR_DUMMY1

    { SID_ATTR_PARA_LINESPACE, true },     // RES_PARATR_LINESPACING
    { SID_ATTR_PARA_ADJUST, true },        // RES_PARATR_ADJUST
    { SID_ATTR_PARA_SPLIT, true },         // RES_PARATR_SPLIT
    { SID_ATTR_PARA_ORPHANS, true },       // RES_PARATR_ORPHANS
    { SID_ATTR_PARA_WIDOWS, true },        // RES_PARATR_WIDOWS
    { SID_ATTR_TABSTOP, true },            // RES_PARATR_TABSTOP
    { SID_ATTR_PARA_HYPHENZONE, true },    // RES_PARATR_HYPHENZONE
    { FN_FORMAT_DROPCAPS, false },              // RES_PARATR_DROP
    { SID_ATTR_PARA_REGISTER, true },      // RES_PARATR_REGISTER
    { SID_ATTR_PARA_NUMRULE, true },       // RES_PARATR_NUMRULE
    { SID_ATTR_PARA_SCRIPTSPACE, true },   // RES_PARATR_SCRIPTSPACE
    { SID_ATTR_PARA_HANGPUNCTUATION, true },// RES_PARATR_HANGINGPUNCTUATION
    { SID_ATTR_PARA_LINESPACE,          false, true },  // RES_PARATR_LINESPACING
    { SID_ATTR_PARA_ADJUST,             false, true },  // RES_PARATR_ADJUST
    { SID_ATTR_PARA_SPLIT,              false, true },  // RES_PARATR_SPLIT
    { SID_ATTR_PARA_ORPHANS,            false, true },  // RES_PARATR_ORPHANS
    { SID_ATTR_PARA_WIDOWS,             false, true },  // RES_PARATR_WIDOWS
    { SID_ATTR_TABSTOP,                 true,  true },  // RES_PARATR_TABSTOP
    { SID_ATTR_PARA_HYPHENZONE,         false, true },  // RES_PARATR_HYPHENZONE
    { FN_FORMAT_DROPCAPS,               false, false }, // RES_PARATR_DROP
    { SID_ATTR_PARA_REGISTER,           false, true },  // RES_PARATR_REGISTER
    { SID_ATTR_PARA_NUMRULE,            false, true },  // RES_PARATR_NUMRULE
    { SID_ATTR_PARA_SCRIPTSPACE,        false, true },  // RES_PARATR_SCRIPTSPACE
    { SID_ATTR_PARA_HANGPUNCTUATION,    false, true },  // RES_PARATR_HANGINGPUNCTUATION

    { SID_ATTR_PARA_FORBIDDEN_RULES, true },// RES_PARATR_FORBIDDEN_RULES
    { SID_PARA_VERTALIGN, true },          // RES_PARATR_VERTALIGN
    { SID_ATTR_PARA_SNAPTOGRID, true },    // RES_PARATR_SNAPTOGRID
    { SID_ATTR_BORDER_CONNECT, true },     // RES_PARATR_CONNECT_BORDER
    { SID_ATTR_PARA_FORBIDDEN_RULES,    false, true },  // RES_PARATR_FORBIDDEN_RULES
    { SID_PARA_VERTALIGN,               false, true },  // RES_PARATR_VERTALIGN
    { SID_ATTR_PARA_SNAPTOGRID,         false, true },  // RES_PARATR_SNAPTOGRID
    { SID_ATTR_BORDER_CONNECT,          false, true },  // RES_PARATR_CONNECT_BORDER

    { SID_ATTR_PARA_OUTLINE_LEVEL, true }, // RES_PARATR_OUTLINELEVEL //#outline level
    { 0, true },                           // RES_PARATR_RSID
    { SID_ATTR_PARA_GRABBAG, true },       // RES_PARATR_GRABBAG
    { 0, true },                           // RES_PARATR_LIST_ID
    { 0, true },                           // RES_PARATR_LIST_LEVEL
    { 0, true },                           // RES_PARATR_LIST_ISRESTART
    { 0, true },                           // RES_PARATR_LIST_RESTARTVALUE
    { 0, true },                           // RES_PARATR_LIST_ISCOUNTED
    { 0, true },                           // RES_PARATR_LIST_AUTOFMT
    { SID_ATTR_PARA_OUTLINE_LEVEL,      false, true },  // RES_PARATR_OUTLINELEVEL //#outline level
    { 0,                                false, true },  // RES_PARATR_RSID
    { SID_ATTR_PARA_GRABBAG,            false, true },  // RES_PARATR_GRABBAG
    { 0,                                false, true },  // RES_PARATR_LIST_ID
    { 0,                                false, true },  // RES_PARATR_LIST_LEVEL
    { 0,                                false, true },  // RES_PARATR_LIST_ISRESTART
    { 0,                                false, true },  // RES_PARATR_LIST_RESTARTVALUE
    { 0,                                false, true },  // RES_PARATR_LIST_ISCOUNTED
    { 0,                                false, true },  // RES_PARATR_LIST_AUTOFMT

    { 0, true },                           // RES_FILL_ORDER
    { 0, true },                           // RES_FRM_SIZE
    { SID_ATTR_PAGE_PAPERBIN, true },      // RES_PAPER_BIN
    { SID_ATTR_PARA_FIRSTLINESPACE, true }, // RES_MARGIN_FIRSTLINE
    { SID_ATTR_PARA_LEFTSPACE, true },      // RES_MARGIN_TEXTLEFT
    { SID_ATTR_PARA_RIGHTSPACE, true },     // RES_MARGIN_RIGHT
    { 0, true },                            // RES_MARGIN_LEFT
    { 0, true },                            // RES_MARGIN_GUTTER
    { 0, true },                            // RES_MARGIN_GUTTER_RIGHT
    { SID_ATTR_LRSPACE, true },            // RES_LR_SPACE
    { SID_ATTR_ULSPACE, true },            // RES_UL_SPACE
    { 0, false },                               // RES_PAGEDESC
    { SID_ATTR_PARA_PAGEBREAK, true },     // RES_BREAK
    { 0, false },                               // RES_CNTNT
    { 0, true },                           // RES_HEADER
    { 0, true },                           // RES_FOOTER
    { 0, true },                           // RES_PRINT
    { FN_OPAQUE, true },                   // RES_OPAQUE
    { FN_SET_PROTECT, true },              // RES_PROTECT
    { FN_SURROUND, true },                 // RES_SURROUND
    { FN_VERT_ORIENT, true },              // RES_VERT_ORIENT
    { FN_HORI_ORIENT, true },              // RES_HORI_ORIENT
    { 0, false },                               // RES_ANCHOR
    { SID_ATTR_BRUSH, true },              // RES_BACKGROUND
    { SID_ATTR_BORDER_OUTER, true },       // RES_BOX
    { SID_ATTR_BORDER_SHADOW, true },      // RES_SHADOW
    { SID_ATTR_MACROITEM, true },          // RES_FRMMACRO
    { FN_ATTR_COLUMNS, true },             // RES_COL
    { SID_ATTR_PARA_KEEP, true },          // RES_KEEP
    { 0, true },                           // RES_URL
    { 0, true },                           // RES_EDIT_IN_READONLY
    { 0,                                false, true },  // RES_FILL_ORDER
    { 0,                                false, true },  // RES_FRM_SIZE
    { SID_ATTR_PAGE_PAPERBIN,           false, true },  // RES_PAPER_BIN
    { SID_ATTR_PARA_FIRSTLINESPACE,     false, true },  // RES_MARGIN_FIRSTLINE
    { SID_ATTR_PARA_LEFTSPACE,          false, true },  // RES_MARGIN_TEXTLEFT
    { SID_ATTR_PARA_RIGHTSPACE,         false, true },  // RES_MARGIN_RIGHT
    { 0,                                false, true },  // RES_MARGIN_LEFT
    { 0,                                false, true },  // RES_MARGIN_GUTTER
    { 0,                                false, true },  // RES_MARGIN_GUTTER_RIGHT
    { SID_ATTR_LRSPACE,                 false, true },  // RES_LR_SPACE
    { SID_ATTR_ULSPACE,                 false, true },  // RES_UL_SPACE
    { 0,                                true,  false }, // RES_PAGEDESC
    { SID_ATTR_PARA_PAGEBREAK,          false, true },  // RES_BREAK
    { 0,                                false, false }, // RES_CNTNT
    { 0,                                false, true },  // RES_HEADER
    { 0,                                false, true },  // RES_FOOTER
    { 0,                                false, true },  // RES_PRINT
    { FN_OPAQUE,                        false, true },  // RES_OPAQUE
    { FN_SET_PROTECT,                   false, true },  // RES_PROTECT
    { FN_SURROUND,                      false, true },  // RES_SURROUND
    { FN_VERT_ORIENT,                   false, true },  // RES_VERT_ORIENT
    { FN_HORI_ORIENT,                   false, true },  // RES_HORI_ORIENT
    { 0,                                false, false }, // RES_ANCHOR
    { SID_ATTR_BRUSH,                   true,  true },  // RES_BACKGROUND
    { SID_ATTR_BORDER_OUTER,            true,  true },  // RES_BOX
    { SID_ATTR_BORDER_SHADOW,           true,  true },  // RES_SHADOW
    { SID_ATTR_MACROITEM,               false, true },  // RES_FRMMACRO
    { FN_ATTR_COLUMNS,                  false, true },  // RES_COL
    { SID_ATTR_PARA_KEEP,               false, true },  // RES_KEEP
    { 0,                                true,  true },  // RES_URL
    { 0,                                false, true },  // RES_EDIT_IN_READONLY

    { 0, true },                           // RES_LAYOUT_SPLIT
    { 0, false },                               // RES_CHAIN
    { 0, true },                           // RES_TEXTGRID
    { FN_FORMAT_LINENUMBER, true },        // RES_LINENUMBER
    { 0, true },                           // RES_FTN_AT_TXTEND
    { 0, true },                           // RES_END_AT_TXTEND
    { 0, true },                           // RES_COLUMNBALANCE
    { 0,                                false, true },  // RES_LAYOUT_SPLIT
    { 0,                                false, false }, // RES_CHAIN
    { 0,                                false, true },  // RES_TEXTGRID
    { FN_FORMAT_LINENUMBER,             false, true },  // RES_LINENUMBER
    { 0,                                false, true },  // RES_FTN_AT_TXTEND
    { 0,                                false, true },  // RES_END_AT_TXTEND
    { 0,                                false, true },  // RES_COLUMNBALANCE

    { SID_ATTR_FRAMEDIRECTION, true },     // RES_FRAMEDIR
    { SID_ATTR_FRAMEDIRECTION,          false, true },  // RES_FRAMEDIR

    { SID_ATTR_HDFT_DYNAMIC_SPACING, true },// RES_HEADER_FOOTER_EAT_SPACING
    { FN_TABLE_ROW_SPLIT, true },          // RES_ROW_SPLIT
    { 0, true }                 ,          // RES_FLY_SPLIT
    { SID_ATTR_HDFT_DYNAMIC_SPACING,    false, true },  // RES_HEADER_FOOTER_EAT_SPACING
    { FN_TABLE_ROW_SPLIT,               false, true },  // RES_ROW_SPLIT
    { 0,                                false, true },  // RES_FLY_SPLIT
    // #i18732# - use slot-id define in svx
    { SID_SW_FOLLOW_TEXT_FLOW, true },     // RES_FOLLOW_TEXT_FLOW
    { SID_SW_FOLLOW_TEXT_FLOW,          false, true },  // RES_FOLLOW_TEXT_FLOW
    // #i29550#
    { SID_SW_COLLAPSING_BORDERS, true },   // RES_COLLAPSING_BORDERS
    { SID_SW_COLLAPSING_BORDERS,        false, true },  // RES_COLLAPSING_BORDERS
    // #i28701#
    { SID_SW_WRAP_INFLUENCE_ON_OBJPOS, true },// RES_WRAP_INFLUENCE_ON_OBJPOS
    { 0, false },                               // RES_AUTO_STYLE
    { 0, true },                           // RES_FRMATR_STYLE_NAME
    { 0, true },                           // RES_FRMATR_CONDITIONAL_STYLE_NAME
    { 0, true },                           // RES_FRMATR_GRABBAG
    { 0, true },                           // RES_TEXT_VERT_ADJUST
    { 0, true },                           // RES_BACKGROUND_FULL_SIZE
    { 0, true },                           // RES_RTL_GUTTER
    { 0, true },                           // RES_DECORATIVE
    { SID_SW_WRAP_INFLUENCE_ON_OBJPOS,  false, true },  // RES_WRAP_INFLUENCE_ON_OBJPOS
    { 0,                                false, false }, // RES_AUTO_STYLE
    { 0,                                false, true },  // RES_FRMATR_STYLE_NAME
    { 0,                                false, true },  // RES_FRMATR_CONDITIONAL_STYLE_NAME
    { 0,                                false, true },  // RES_FRMATR_GRABBAG
    { 0,                                false, true },  // RES_TEXT_VERT_ADJUST
    { 0,                                false, true },  // RES_BACKGROUND_FULL_SIZE
    { 0,                                false, true },  // RES_RTL_GUTTER
    { 0,                                false, true },  // RES_DECORATIVE

    { 0, true },                           // RES_GRFATR_MIRRORGRF
    { SID_ATTR_GRAF_CROP, true },          // RES_GRFATR_CROPGRF
    { 0, true },                           // RES_GRFATR_ROTATION,
    { 0, true },                           // RES_GRFATR_LUMINANCE,
    { 0, true },                           // RES_GRFATR_CONTRAST,
    { 0, true },                           // RES_GRFATR_CHANNELR,
    { 0, true },                           // RES_GRFATR_CHANNELG,
    { 0, true },                           // RES_GRFATR_CHANNELB,
    { 0, true },                           // RES_GRFATR_GAMMA,
    { 0, true },                           // RES_GRFATR_INVERT,
    { 0, true },                           // RES_GRFATR_TRANSPARENCY,
    { 0, true },                           // RES_GRFATR_DUMMY3,
    { 0, true },                           // RES_GRFATR_DUMMY4,
    { 0, true },                           // RES_GRFATR_DUMMY5,
    { 0, true },                           // RES_GRFATR_DUMMY6,
    { 0,                                false, true },  // RES_GRFATR_MIRRORGRF
    { SID_ATTR_GRAF_CROP,               false, true },  // RES_GRFATR_CROPGRF
    { 0,                                false, true },  // RES_GRFATR_ROTATION,
    { 0,                                false, true },  // RES_GRFATR_LUMINANCE,
    { 0,                                false, true },  // RES_GRFATR_CONTRAST,
    { 0,                                false, true },  // RES_GRFATR_CHANNELR,
    { 0,                                false, true },  // RES_GRFATR_CHANNELG,
    { 0,                                false, true },  // RES_GRFATR_CHANNELB,
    { 0,                                false, true },  // RES_GRFATR_GAMMA,
    { 0,                                false, true },  // RES_GRFATR_INVERT,
    { 0,                                false, true },  // RES_GRFATR_TRANSPARENCY,
    { 0,                                false, true },  // RES_GRFATR_DUMMY3,
    { 0,                                false, true },  // RES_GRFATR_DUMMY4,
    { 0,                                false, true },  // RES_GRFATR_DUMMY5,
    { 0,                                false, true },  // RES_GRFATR_DUMMY6,

    { 0, true },                           // RES_BOXATR_FORMAT
    { 0, false },                               // RES_BOXATR_FORMULA,
    { 0, true },                           // RES_BOXATR_VALUE
    { 0,                                false, true },  // RES_BOXATR_FORMAT
    { 0,                                true,  false }, // RES_BOXATR_FORMULA,
    { 0,                                false, true },  // RES_BOXATR_VALUE

    { 0, true }                            // RES_UNKNOWNATR_CONTAINER
    { 0,                                true,  true }   // RES_UNKNOWNATR_CONTAINER
};

std::vector<SvGlobalName> *pGlobalOLEExcludeList = nullptr;
diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx
index 05ea83b..acee839 100644
--- a/sw/source/core/crsr/crstrvl.cxx
+++ b/sw/source/core/crsr/crstrvl.cxx
@@ -416,12 +416,13 @@ bool SwCursorShell::GotoNxtPrvTableFormula( bool bNext, bool bOnlyErrors )
                                &rPos, &tmp) );
    }

    sal_uInt32 nMaxItems = GetDoc()->GetAttrPool().GetItemCount2( RES_BOXATR_FORMULA );
    const registeredSfxPoolItems& rSurrogates(GetDoc()->GetAttrPool().GetItemSurrogates(RES_BOXATR_FORMULA));
    const sal_uInt32 nMaxItems(rSurrogates.size());
    if( nMaxItems > 0 )
    {
        sal_uInt8 nMaxDo = 2;
        do {
            for (const SfxPoolItem* pItem : GetDoc()->GetAttrPool().GetItemSurrogates(RES_BOXATR_FORMULA))
            for (const SfxPoolItem* pItem : rSurrogates)
            {
                const SwTableBox* pTBox;
                auto pFormulaItem = dynamic_cast<const SwTableBoxFormula*>(pItem);
@@ -521,7 +522,8 @@ bool SwCursorShell::GotoNxtPrvTOXMark( bool bNext )

    const SwTextNode* pTextNd;
    const SwTextTOXMark* pTextTOX;
    sal_uInt32 nMaxItems = GetDoc()->GetAttrPool().GetItemCount2( RES_TXTATR_TOXMARK );
    const registeredSfxPoolItems& rSurrogates(GetDoc()->GetAttrPool().GetItemSurrogates(RES_TXTATR_TOXMARK));
    const sal_uInt32 nMaxItems(rSurrogates.size());
    if( nMaxItems == 0 )
    {
        SvxSearchDialogWrapper::SetSearchLabel( SearchLabel::NavElementNotFound );
@@ -529,7 +531,7 @@ bool SwCursorShell::GotoNxtPrvTOXMark( bool bNext )
    }

    do {
        for (const SfxPoolItem* pItem : GetDoc()->GetAttrPool().GetItemSurrogates(RES_TXTATR_TOXMARK))
        for (const SfxPoolItem* pItem : rSurrogates)
        {
            auto pToxMarkItem = dynamic_cast<const SwTOXMark*>(pItem);
            if( !pToxMarkItem )
diff --git a/sw/source/core/doc/docbasic.cxx b/sw/source/core/doc/docbasic.cxx
index c28a15f..697559b 100644
--- a/sw/source/core/doc/docbasic.cxx
+++ b/sw/source/core/doc/docbasic.cxx
@@ -143,7 +143,7 @@ sal_uInt16 SwDoc::CallEvent( SvMacroItemId nEvent, const SwCallMouseEvent& rCall
            for (const SfxPoolItem* pItem : GetAttrPool().GetItemSurrogates(RES_TXTATR_INETFMT))
            {
                auto pFormatItem = dynamic_cast<const SwFormatINetFormat*>(pItem);
                if( pFormatItem && rCallEvent.PTR.pINetAttr == pFormatItem )
                if( pFormatItem && SfxPoolItem::areSame(rCallEvent.PTR.pINetAttr, pFormatItem) )
                {
                    bCheckPtr = false;       // misuse as a flag
                    break;
diff --git a/sw/source/core/doc/doctxm.cxx b/sw/source/core/doc/doctxm.cxx
index 82051e0..f03687d 100644
--- a/sw/source/core/doc/doctxm.cxx
+++ b/sw/source/core/doc/doctxm.cxx
@@ -247,7 +247,8 @@ const SwTOXMark& SwDoc::GotoTOXMark( const SwTOXMark& rCurTOXMark,

    for(SwTOXMark* pTOXMark : aMarks)
    {
        if ( pTOXMark == &rCurTOXMark )
        // Item PtrCompare needed here
        if (areSfxPoolItemPtrsEqual( pTOXMark, &rCurTOXMark ))
            continue;

        pMark = pTOXMark->GetTextTOXMark();
diff --git a/sw/source/core/doc/fmtcol.cxx b/sw/source/core/doc/fmtcol.cxx
index 5561b88..4d87241 100644
--- a/sw/source/core/doc/fmtcol.cxx
+++ b/sw/source/core/doc/fmtcol.cxx
@@ -237,7 +237,7 @@ void SwTextFormatColl::SwClientNotify(const SwModify& rModify, const SfxHint& rH
    const SvxFirstLineIndentItem *pOldFirstLineIndent(GetItemIfSet(RES_MARGIN_FIRSTLINE, false));
    if (pNewFirstLineIndent && pOldFirstLineIndent)
    {
        if (pOldFirstLineIndent != pNewFirstLineIndent) // Avoid recursion (SetAttr!)
        if (!SfxPoolItem::areSame(pOldFirstLineIndent, pNewFirstLineIndent)) // Avoid recursion (SetAttr!)
        {
            bool bChg = false;
            SvxFirstLineIndentItem aNew(*pOldFirstLineIndent);
@@ -263,7 +263,7 @@ void SwTextFormatColl::SwClientNotify(const SwModify& rModify, const SfxHint& rH
    const SvxTextLeftMarginItem *pOldTextLeftMargin(GetItemIfSet(RES_MARGIN_TEXTLEFT, false));
    if (pNewTextLeftMargin && pOldTextLeftMargin)
    {
        if (pOldTextLeftMargin != pNewTextLeftMargin) // Avoid recursion (SetAttr!)
        if (!SfxPoolItem::areSame(pOldTextLeftMargin, pNewTextLeftMargin)) // Avoid recursion (SetAttr!)
        {
            bool bChg = false;
            SvxTextLeftMarginItem aNew(*pOldTextLeftMargin);
@@ -289,7 +289,7 @@ void SwTextFormatColl::SwClientNotify(const SwModify& rModify, const SfxHint& rH
    const SvxRightMarginItem *pOldRightMargin(GetItemIfSet(RES_MARGIN_RIGHT, false));
    if (pNewRightMargin && pOldRightMargin)
    {
        if (pOldRightMargin != pNewRightMargin) // Avoid recursion (SetAttr!)
        if (!SfxPoolItem::areSame(pOldRightMargin, pNewRightMargin)) // Avoid recursion (SetAttr!)
        {
            bool bChg = false;
            SvxRightMarginItem aNew(*pOldRightMargin);
@@ -313,7 +313,7 @@ void SwTextFormatColl::SwClientNotify(const SwModify& rModify, const SfxHint& rH
    }

    if( pNewULSpace && (pOldULSpace = GetItemIfSet(RES_UL_SPACE, false)) &&
        pOldULSpace != pNewULSpace )    // Avoid recursion (SetAttr!)
        !SfxPoolItem::areSame(pOldULSpace, pNewULSpace) )    // Avoid recursion (SetAttr!)
    {
        SvxULSpaceItem aNew( *pOldULSpace );
        bool bChg = false;
@@ -348,7 +348,7 @@ void SwTextFormatColl::SwClientNotify(const SwModify& rModify, const SfxHint& rH
        if( pFSize && (SfxItemState::SET == GetItemState(
            pFSize->Which(), false, reinterpret_cast<const SfxPoolItem**>(&pOldFSize) )) &&
            // Avoid recursion (SetAttr!)
            pFSize != pOldFSize )
            !SfxPoolItem::areSame(pFSize, pOldFSize) )
        {
            if( 100 == pOldFSize->GetProp() &&
                MapUnit::MapRelative == pOldFSize->GetPropUnit() )
diff --git a/sw/source/core/docnode/node.cxx b/sw/source/core/docnode/node.cxx
index 6cfab78..b2419bd 100644
--- a/sw/source/core/docnode/node.cxx
+++ b/sw/source/core/docnode/node.cxx
@@ -1174,13 +1174,13 @@ void SwContentNode::SwClientNotify( const SwModify&, const SfxHint& rHint)
                // Thus we are asserting here, but falling back to an proper
                // hint instead. so that we at least will not spread such poison further.
#ifdef DBG_UTIL
                if(pLegacyHint->m_pNew != pLegacyHint->m_pOld)
                if (!SfxPoolItem::areSame(pLegacyHint->m_pNew, pLegacyHint->m_pOld))
                {
                    auto pBT = sal::backtrace_get(20);
                    SAL_WARN("sw.core", "UpdateAttr not matching! " << sal::backtrace_to_string(pBT.get()));
                }
#endif
                assert(pLegacyHint->m_pNew == pLegacyHint->m_pOld);
                assert(SfxPoolItem::areSame(pLegacyHint->m_pNew, pLegacyHint->m_pOld));
                assert(dynamic_cast<const SwUpdateAttr*>(pLegacyHint->m_pNew));
                const SwUpdateAttr aFallbackHint(0,0,0);
                const SwUpdateAttr& rUpdateAttr = pLegacyHint->m_pNew ? *static_cast<const SwUpdateAttr*>(pLegacyHint->m_pNew) : aFallbackHint;
diff --git a/sw/source/core/layout/atrfrm.cxx b/sw/source/core/layout/atrfrm.cxx
index b3dd57c..ee4a451 100644
--- a/sw/source/core/layout/atrfrm.cxx
+++ b/sw/source/core/layout/atrfrm.cxx
@@ -634,9 +634,6 @@ SwFormatPageDesc::SwFormatPageDesc( const SwFormatPageDesc &rCpy )
    m_oNumOffset( rCpy.m_oNumOffset ),
    m_pDefinedIn( nullptr )
{
    // ITEM: mark this Item to be non-shareable/non-RefCountable. For more
    // info see comment @SwAttrSet::SetModifyAtAttr
    m_bShareable = false;
}

SwFormatPageDesc::SwFormatPageDesc( const SwPageDesc *pDesc )
@@ -644,14 +641,11 @@ SwFormatPageDesc::SwFormatPageDesc( const SwPageDesc *pDesc )
    SwClient( const_cast<SwPageDesc*>(pDesc) ),
    m_pDefinedIn( nullptr )
{
    // ITEM: mark this Item to be non-shareable/non-RefCountable. For more
    // info see comment @SwAttrSet::SetModifyAtAttr
    m_bShareable = false;
}

SwFormatPageDesc &SwFormatPageDesc::operator=(const SwFormatPageDesc &rCpy)
{
    if(this == &rCpy)
    if (SfxPoolItem::areSame(this, &rCpy))
        return *this;

    if (rCpy.GetPageDesc())
@@ -865,7 +859,7 @@ SwFormatCol::~SwFormatCol() {}

SwFormatCol& SwFormatCol::operator=( const SwFormatCol& rCpy )
{
    if (this != &rCpy)
    if (!SfxPoolItem::areSame(this, &rCpy))
    {
        m_eLineStyle  = rCpy.m_eLineStyle;
        m_nLineWidth  = rCpy.m_nLineWidth;
@@ -1650,7 +1644,7 @@ sal_Int32 SwFormatAnchor::GetAnchorContentOffset() const

SwFormatAnchor& SwFormatAnchor::operator=(const SwFormatAnchor& rAnchor)
{
    if (this != &rAnchor)
    if (!SfxPoolItem::areSame(this, &rAnchor))
    {
        m_eAnchorId  = rAnchor.m_eAnchorId;
        m_nPageNumber   = rAnchor.m_nPageNumber;
diff --git a/sw/source/core/layout/sectfrm.cxx b/sw/source/core/layout/sectfrm.cxx
index 7afcb6b..fdbcb5a 100644
--- a/sw/source/core/layout/sectfrm.cxx
+++ b/sw/source/core/layout/sectfrm.cxx
@@ -147,7 +147,7 @@ void SwSectionFrame::Init()
    {
        const SwFormatCol *pOld = Lower() ? &rCol : new SwFormatCol;
        ChgColumns( *pOld, rCol, IsAnyNoteAtEnd() );
        if( pOld != &rCol )
        if (!SfxPoolItem::areSame( pOld, &rCol ))
            delete pOld;
    }
}
diff --git a/sw/source/core/para/paratr.cxx b/sw/source/core/para/paratr.cxx
index 7d57bcd..f724ac2 100644
--- a/sw/source/core/para/paratr.cxx
+++ b/sw/source/core/para/paratr.cxx
@@ -44,9 +44,6 @@ SwFormatDrop::SwFormatDrop()
    m_nChars( 0 ),
    m_bWholeWord( false )
{
    // ITEM: mark this Item to be non-shareable/non-RefCountable. For more
    // info see comment @SwAttrSet::SetModifyAtAttr
    m_bShareable = false;
}

SwFormatDrop::SwFormatDrop( const SwFormatDrop &rCpy )
@@ -58,9 +55,6 @@ SwFormatDrop::SwFormatDrop( const SwFormatDrop &rCpy )
    m_nChars( rCpy.GetChars() ),
    m_bWholeWord( rCpy.GetWholeWord() )
{
    // ITEM: mark this Item to be non-shareable/non-RefCountable. For more
    // info see comment @SwAttrSet::SetModifyAtAttr
    m_bShareable = false;
}

SwFormatDrop::~SwFormatDrop()
diff --git a/sw/source/core/table/swnewtable.cxx b/sw/source/core/table/swnewtable.cxx
index 4e1386f..3cc2e367 100644
--- a/sw/source/core/table/swnewtable.cxx
+++ b/sw/source/core/table/swnewtable.cxx
@@ -2383,7 +2383,7 @@ bool SwTable::CanConvertSubtables() const
    {
        return false; // no formulas in fields yet
    }
    if (pDoc->GetAttrPool().GetItemCount2(RES_BOXATR_FORMULA) != 0)
    if (pDoc->GetAttrPool().GetItemSurrogates(RES_BOXATR_FORMULA).size() != 0)
    {
        return false; // no table box formulas yet
    }
diff --git a/sw/source/core/table/swtable.cxx b/sw/source/core/table/swtable.cxx
index d50c493..a5540a4 100644
--- a/sw/source/core/table/swtable.cxx
+++ b/sw/source/core/table/swtable.cxx
@@ -1630,16 +1630,16 @@ bool SwTable::IsDeleted() const

void SwTable::GatherFormulas(std::vector<SwTableBoxFormula*>& rvFormulas)
{
    for(SfxPoolItem* pItem: GetFrameFormat()->GetDoc()->GetAttrPool().GetItemSurrogates(RES_BOXATR_FORMULA))
    for(const SfxPoolItem* pItem: GetFrameFormat()->GetDoc()->GetAttrPool().GetItemSurrogates(RES_BOXATR_FORMULA))
    {
        auto pBoxFormula = dynamic_cast<SwTableBoxFormula*>(pItem);
        auto pBoxFormula = dynamic_cast<const SwTableBoxFormula*>(pItem);
        assert(pBoxFormula); // use StaticWhichCast instead?
        if(!pBoxFormula->GetDefinedIn())
            continue;
        const SwNode* pNd = pBoxFormula->GetNodeOfFormula();
        if(!pNd || &pNd->GetNodes() != &pNd->GetDoc().GetNodes()) // is this ever valid or should we assert here?
            continue;
        rvFormulas.push_back(pBoxFormula);
        rvFormulas.push_back(const_cast<SwTableBoxFormula*>(pBoxFormula));
    }
}

diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index 358d6d5..24203ec 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -659,9 +659,9 @@ static bool CanSkipOverRedline(
    }
    for (size_t i = 0; i < SAL_N_ELEMENTS(activeCharAttrsStart); ++i)
    {
        // all of these are poolable
//        assert(!activeCharAttrsStart[i] || activeCharAttrsStart[i]->GetItemPool()->IsItemPoolable(*activeCharAttrsStart[i]));
        if (activeCharAttrsStart[i] != activeCharAttrsEnd[i])
        // all of these should be shareable (but we have no SfxItemPool to check it here)
        // assert(!activeCharAttrsStart[i] || activeCharAttrsStart[i]->GetItemPool()->Shareable(*activeCharAttrsStart[i]));
        if (!SfxPoolItem::areSame(activeCharAttrsStart[i], activeCharAttrsEnd[i]))
        {
            if (!isTheAnswerYes) return false;
        }
diff --git a/sw/source/core/text/pormulti.cxx b/sw/source/core/text/pormulti.cxx
index 67cd13a..4e72686 100644
--- a/sw/source/core/text/pormulti.cxx
+++ b/sw/source/core/text/pormulti.cxx
@@ -1080,7 +1080,7 @@ std::optional<SwMultiCreator> SwTextSizeInfo::GetMultiCreator(TextFrameIndex &rP
        return aRet;
    }
    if (pActiveTwoLinesHint ||
        (pNodeTwoLinesItem && pNodeTwoLinesItem == pActiveTwoLinesItem &&
        (pNodeTwoLinesItem && SfxPoolItem::areSame(pNodeTwoLinesItem, pActiveTwoLinesItem) &&
         rPos < TextFrameIndex(GetText().getLength())))
    {   // The winner is a 2-line-attribute,
        // the end of the multiportion depends on the following attributes...
@@ -1228,7 +1228,7 @@ std::optional<SwMultiCreator> SwTextSizeInfo::GetMultiCreator(TextFrameIndex &rP
        return aRet;
    }
    if (pActiveRotateHint ||
        (pNodeRotateItem && pNodeRotateItem == pActiveRotateItem &&
        (pNodeRotateItem && SfxPoolItem::areSame(pNodeRotateItem, pActiveRotateItem) &&
         rPos < TextFrameIndex(GetText().getLength())))
    {   // The winner is a rotate-attribute,
        // the end of the multiportion depends on the following attributes...
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index a86dfca..470ce8b 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -2459,7 +2459,7 @@ void SwTextFrame::SwClientNotify(SwModify const& rModify, SfxHint const& rHint)
                nPos = MapModelToView(&rNode, nNPos);
                if (IsIdxInside(nPos, TextFrameIndex(1)))
                {
                    if( pNew == pOld )
                    if (SfxPoolItem::areSame( pNew, pOld ))
                    {
                        // only repaint
                        // opt: invalidate window?
@@ -2518,7 +2518,7 @@ void SwTextFrame::SwClientNotify(SwModify const& rModify, SfxHint const& rHint)
                {
                    const SfxPoolItem* pOldItem = pOld ?
                        &(static_cast<const SwAttrSetChg*>(pOld)->GetChgSet()->Get(RES_TXTATR_FIELD)) : nullptr;
                    if( pItem == pOldItem )
                    if (SfxPoolItem::areSame( pItem, pOldItem ))
                    {
                        InvalidatePage();
                        SetCompletePaint();
diff --git a/sw/source/core/txtnode/attrcontentcontrol.cxx b/sw/source/core/txtnode/attrcontentcontrol.cxx
index 34db9fd..1782f23 100644
--- a/sw/source/core/txtnode/attrcontentcontrol.cxx
+++ b/sw/source/core/txtnode/attrcontentcontrol.cxx
@@ -67,7 +67,9 @@ SwFormatContentControl::SwFormatContentControl(

SwFormatContentControl::~SwFormatContentControl()
{
    if (m_pContentControl && (m_pContentControl->GetFormatContentControl() == this))
    if (m_pContentControl
        // SwFormatContentControl is not shareable, so ptr compare is OK
        && areSfxPoolItemPtrsEqual(m_pContentControl->GetFormatContentControl(), this))
    {
        NotifyChangeTextNode(nullptr);
        m_pContentControl->SetFormatContentControl(nullptr);
@@ -116,7 +118,8 @@ void SwFormatContentControl::SetTextAttr(SwTextContentControl* pTextAttr)
        {
            m_pContentControl->SetFormatContentControl(this);
        }
        else if (m_pContentControl->GetFormatContentControl() == this)
        // SwFormatContentControl is not shareable, so ptr compare is OK
        else if (areSfxPoolItemPtrsEqual(m_pContentControl->GetFormatContentControl(), this))
        {
            // The text attribute is gone, so de-register from text node.
            NotifyChangeTextNode(nullptr);
@@ -132,7 +135,9 @@ void SwFormatContentControl::NotifyChangeTextNode(SwTextNode* pTextNode)
    {
        SAL_WARN("sw.core", "SwFormatContentControl::NotifyChangeTextNode: no content control?");
    }
    if (m_pContentControl && (m_pContentControl->GetFormatContentControl() == this))
    if (m_pContentControl
        // SwFormatContentControl is not shareable, so ptr compare is OK
        && areSfxPoolItemPtrsEqual(m_pContentControl->GetFormatContentControl(), this))
    {
        // Not calling Modify, that would call SwXContentControl::SwClientNotify.
        m_pContentControl->NotifyChangeTextNode(pTextNode);
diff --git a/sw/source/core/txtnode/fmtatr2.cxx b/sw/source/core/txtnode/fmtatr2.cxx
index 7792d01..3a57680 100644
--- a/sw/source/core/txtnode/fmtatr2.cxx
+++ b/sw/source/core/txtnode/fmtatr2.cxx
@@ -428,7 +428,8 @@ SwFormatRuby::~SwFormatRuby()

SwFormatRuby& SwFormatRuby::operator=( const SwFormatRuby& rAttr )
{
    if(this == &rAttr)
    // SwFormatRuby is not shareable, so ptr compare is OK
    if (areSfxPoolItemPtrsEqual(this, &rAttr))
        return *this;

    m_sRubyText = rAttr.m_sRubyText;
@@ -568,7 +569,8 @@ SwFormatMeta::SwFormatMeta( std::shared_ptr< ::sw::Meta > i_pMeta,

SwFormatMeta::~SwFormatMeta()
{
    if (m_pMeta && (m_pMeta->GetFormatMeta() == this))
    // SwFormatMeta is not shareable, so ptr compare is OK
    if (m_pMeta && areSfxPoolItemPtrsEqual(m_pMeta->GetFormatMeta(), this))
    {
        NotifyChangeTextNode(nullptr);
        m_pMeta->SetFormatMeta(nullptr);
@@ -603,7 +605,8 @@ void SwFormatMeta::SetTextAttr(SwTextMeta * const i_pTextAttr)
        {
            m_pMeta->SetFormatMeta(this);
        }
        else if (m_pMeta->GetFormatMeta() == this)
        // SwFormatMeta is not shareable, so ptr compare is OK
        else if (areSfxPoolItemPtrsEqual(m_pMeta->GetFormatMeta(), this))
        {   // text attribute gone => de-register from text node!
            NotifyChangeTextNode(nullptr);
            m_pMeta->SetFormatMeta(nullptr);
@@ -616,7 +619,8 @@ void SwFormatMeta::NotifyChangeTextNode(SwTextNode *const pTextNode)
    // N.B.: do not reset m_pTextAttr here: see call in nodes.cxx,
    // where the hint is not deleted!
    OSL_ENSURE(m_pMeta, "SwFormatMeta::NotifyChangeTextNode: no Meta?");
    if (m_pMeta && (m_pMeta->GetFormatMeta() == this))
    // SwFormatMeta is not shareable, so ptr compare is OK
    if (m_pMeta && areSfxPoolItemPtrsEqual(m_pMeta->GetFormatMeta(), this))
    {   // do not call Modify, that would call SwXMeta::SwClientNotify
        m_pMeta->NotifyChangeTextNode(pTextNode);
    }
diff --git a/sw/source/core/txtnode/thints.cxx b/sw/source/core/txtnode/thints.cxx
index 71c1ed7..0556fac 100644
--- a/sw/source/core/txtnode/thints.cxx
+++ b/sw/source/core/txtnode/thints.cxx
@@ -899,7 +899,7 @@ void SwpHints::BuildPortions( SwTextNode& rNode, SwTextAttr& rNewHint,
                    {
                        const SfxPoolItem* pTmpItem = nullptr;
                        if ( SfxItemState::SET == rWholeParaAttrSet.GetItemState( pItem->Which(), false, &pTmpItem ) &&
                             pTmpItem == pItem )
                             SfxPoolItem::areSame(pTmpItem, pItem) )
                        {
                            // Do not clear item if the attribute is set in a character format:
                            if ( !pCurrentCharFormat || nullptr == CharFormat::GetItem( *pCurrentCharFormat, pItem->Which() ) )
@@ -936,8 +936,9 @@ void SwpHints::BuildPortions( SwTextNode& rNode, SwTextAttr& rNewHint,
                    do
                    {
                        const SfxPoolItem* pTmpItem = nullptr;
                        // here direct SfxPoolItem ptr comp was wrong, found using SfxPoolItem::areSame
                        if ( SfxItemState::SET == rWholeParaAttrSet.GetItemState( pItem->Which(), false, &pTmpItem ) &&
                             pTmpItem == pItem )
                             SfxPoolItem::areSame(pTmpItem, pItem) )
                        {
                            // Do not clear item if the attribute is set in a character format:
                            if ( !pCurrentCharFormat || nullptr == CharFormat::GetItem( *pCurrentCharFormat, pItem->Which() ) )
@@ -1023,7 +1024,7 @@ SwTextAttr* MakeRedlineTextAttr( SwDoc & rDoc, SfxPoolItem const & rAttr )
    // Put new attribute into pool
    // FIXME: this const_cast is evil!
    SfxPoolItem& rNew =
        const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
        const_cast<SfxPoolItem&>( rDoc.GetAttrPool().DirectPutItemInPool( rAttr ) );
    return new SwTextAttrEnd( rNew, 0, 0 );
}

@@ -1061,7 +1062,7 @@ SwTextAttr* MakeTextAttr(
    // Put new attribute into pool
    // FIXME: this const_cast is evil!
    SfxPoolItem& rNew =
        const_cast<SfxPoolItem&>( rDoc.GetAttrPool().Put( rAttr ) );
        const_cast<SfxPoolItem&>( rDoc.GetAttrPool().DirectPutItemInPool( rAttr ) );

    SwTextAttr* pNew = nullptr;
    switch( rNew.Which() )
@@ -2981,18 +2982,22 @@ static MergeResult lcl_Compare_Attributes(
                    pItem1 = iter1.NextItem();
                if (pItem2 && pItem2->Which() == RES_CHRATR_RSID)
                    pItem2 = iter2.NextItem();
                if (!pItem1 && !pItem2)

                if (nullptr == pItem1 && nullptr == pItem2)
                {
                    eMerge = DIFFER_ONLY_RSID;
                    break;
                }
                if (!pItem1 || !pItem2)

                if (nullptr == pItem1 || nullptr == pItem2)
                {
                    // one ptr is nullptr, not both, that would
                    // have triggered above
                    return DIFFER;
                }
                if (pItem1 != pItem2) // all are poolable

                if (!SfxPoolItem::areSame(*pItem1, *pItem2))
                {
                    assert(IsInvalidItem(pItem1) || IsInvalidItem(pItem2) || pItem1->Which() != pItem2->Which() || *pItem1 != *pItem2);
                    return DIFFER;
                }
                pItem1 = iter1.NextItem();
diff --git a/sw/source/core/txtnode/txatbase.cxx b/sw/source/core/txtnode/txatbase.cxx
index df34786..1d57f0e 100644
--- a/sw/source/core/txtnode/txatbase.cxx
+++ b/sw/source/core/txtnode/txatbase.cxx
@@ -60,7 +60,7 @@ void SwTextAttr::Destroy( SwTextAttr * pToDestroy, SfxItemPool& rPool )
    if (!pToDestroy) return;
    SfxPoolItem * const pAttr = pToDestroy->m_pAttr;
    delete pToDestroy;
    rPool.Remove( *pAttr );
    rPool.DirectRemoveItemFromPool( *pAttr );
}

bool SwTextAttr::operator==( const SwTextAttr& rAttr ) const
diff --git a/sw/source/core/undo/rolbck.cxx b/sw/source/core/undo/rolbck.cxx
index d17c08e..9a18fde9 100644
--- a/sw/source/core/undo/rolbck.cxx
+++ b/sw/source/core/undo/rolbck.cxx
@@ -502,7 +502,7 @@ void SwHistorySetFootnote::SetInDoc( SwDoc* pDoc, bool )
        // set the footnote in the TextNode
        SwFormatFootnote aTemp( m_bEndNote );
        SwFormatFootnote& rNew = const_cast<SwFormatFootnote&>(
                pDoc->GetAttrPool().Put(aTemp) );
                pDoc->GetAttrPool().DirectPutItemInPool(aTemp) );
        if ( !m_FootnoteNumber.isEmpty() )
        {
            rNew.SetNumStr( m_FootnoteNumber );
@@ -1382,7 +1382,7 @@ void SwRegHistory::SwClientNotify(const SwModify&, const SfxHint& rHint)
    if (rHint.GetId() != SfxHintId::SwLegacyModify)
        return;
    auto pLegacyHint = static_cast<const sw::LegacyModifyHint*>(&rHint);
    if ( !(m_pHistory && pLegacyHint->m_pNew && pLegacyHint->m_pOld != pLegacyHint->m_pNew) )
    if ( !(m_pHistory && pLegacyHint->m_pNew && !areSfxPoolItemPtrsEqual(pLegacyHint->m_pOld, pLegacyHint->m_pNew) ) )
        return;

    if ( pLegacyHint->m_pNew->Which() < POOLATTR_END )
diff --git a/sw/source/core/undo/unattr.cxx b/sw/source/core/undo/unattr.cxx
index 66ccb40..7e694e2 100644
--- a/sw/source/core/undo/unattr.cxx
+++ b/sw/source/core/undo/unattr.cxx
@@ -683,7 +683,7 @@ void SwUndoResetAttr::RedoImpl(::sw::UndoRedoContext & rContext)
    break;
    case RES_TXTATR_REFMARK:
    {
        SfxItemPool::Item2Range aRange = rDoc.GetAttrPool().GetItemSurrogates(RES_TXTATR_REFMARK);
        const registeredSfxPoolItems& aRange(rDoc.GetAttrPool().GetItemSurrogates(RES_TXTATR_REFMARK));
        SwHistoryHint* pHistoryHint = GetHistory()[0];
        if (pHistoryHint && HSTRY_SETREFMARKHNT == pHistoryHint->Which())
        {
diff --git a/sw/source/core/undo/undobj1.cxx b/sw/source/core/undo/undobj1.cxx
index 781c5555..f0430b9 100644
--- a/sw/source/core/undo/undobj1.cxx
+++ b/sw/source/core/undo/undobj1.cxx
@@ -648,7 +648,7 @@ void SwUndoSetFlyFormat::RedoImpl(::sw::UndoRedoContext & rContext)

void SwUndoSetFlyFormat::PutAttr( sal_uInt16 nWhich, const SfxPoolItem* pItem )
{
    if( pItem && pItem != GetDfltAttr( nWhich ) )
    if( pItem && !SfxPoolItem::areSame(pItem, GetDfltAttr( nWhich ) ) )
    {
        // Special treatment for this anchor
        if( RES_ANCHOR == nWhich )
diff --git a/sw/source/core/unocore/unorefmk.cxx b/sw/source/core/unocore/unorefmk.cxx
index b86fbc6..43b0690 100644
--- a/sw/source/core/unocore/unorefmk.cxx
+++ b/sw/source/core/unocore/unorefmk.cxx
@@ -284,7 +284,7 @@ SwXReferenceMark::getAnchor()
    {
        SwFormatRefMark const*const pNewMark =
            m_pImpl->m_pDoc->GetRefMark(m_pImpl->m_sMarkName);
        if (pNewMark && (pNewMark == m_pImpl->m_pMarkFormat))
        if (pNewMark && SfxPoolItem::areSame(pNewMark, m_pImpl->m_pMarkFormat))
        {
            SwTextRefMark const*const pTextMark =
                m_pImpl->m_pMarkFormat->GetTextRefMark();
@@ -315,7 +315,7 @@ void SAL_CALL SwXReferenceMark::dispose()
    {
        SwFormatRefMark const*const pNewMark =
            m_pImpl->m_pDoc->GetRefMark(m_pImpl->m_sMarkName);
        if (pNewMark && (pNewMark == m_pImpl->m_pMarkFormat))
        if (pNewMark && SfxPoolItem::areSame(pNewMark, m_pImpl->m_pMarkFormat))
        {
            SwTextRefMark const*const pTextMark =
                m_pImpl->m_pMarkFormat->GetTextRefMark();
@@ -385,7 +385,7 @@ void SAL_CALL SwXReferenceMark::setName(const OUString& rName)
        SwFormatRefMark const*const pCurMark =
            m_pImpl->m_pDoc->GetRefMark(m_pImpl->m_sMarkName);
        if ((rName != m_pImpl->m_sMarkName)
            && pCurMark && (pCurMark == m_pImpl->m_pMarkFormat))
            && pCurMark && SfxPoolItem::areSame(pCurMark, m_pImpl->m_pMarkFormat))
        {
            const UnoActionContext aCont(m_pImpl->m_pDoc);
            SwTextRefMark const*const pTextMark =
diff --git a/sw/source/filter/basflt/fltshell.cxx b/sw/source/filter/basflt/fltshell.cxx
index d33cd0a..731a7c4 100644
--- a/sw/source/filter/basflt/fltshell.cxx
+++ b/sw/source/filter/basflt/fltshell.cxx
@@ -915,7 +915,7 @@ void SwFltAnchorListener::Notify(const SfxHint& rHint)
bool SwFltRedline::operator==(const SfxPoolItem& rItem) const
{
    return SfxPoolItem::operator==(rItem) &&
        this == &rItem;
        SfxPoolItem::areSame(this, &rItem);
}

SwFltRedline* SwFltRedline::Clone( SfxItemPool* ) const
diff --git a/sw/source/filter/writer/writer.cxx b/sw/source/filter/writer/writer.cxx
index 5ed18a2..448a64a 100644
--- a/sw/source/filter/writer/writer.cxx
+++ b/sw/source/filter/writer/writer.cxx
@@ -63,7 +63,7 @@ void Writer_Impl::RemoveFontList( SwDoc& rDoc )
{
    for( const auto& rpFontItem : aFontRemoveLst )
    {
        rDoc.GetAttrPool().Remove( *rpFontItem );
        rDoc.GetAttrPool().DirectRemoveItemFromPool( *rpFontItem );
    }
}

@@ -379,13 +379,13 @@ void Writer::AddFontItem( SfxItemPool& rPool, const SvxFontItem& rFont )
    {
        SvxFontItem aFont( rFont );
        aFont.SetWhich( RES_CHRATR_FONT );
        pItem = &rPool.Put( aFont );
        pItem = &rPool.DirectPutItemInPool( aFont );
    }
    else
        pItem = &rPool.Put( rFont );
        pItem = &rPool.DirectPutItemInPool( rFont );

    if( 1 < pItem->GetRefCount() )
        rPool.Remove( *pItem );
        rPool.DirectRemoveItemFromPool( *pItem );
    else
    {
        m_pImpl->aFontRemoveLst.push_back( pItem );
diff --git a/sw/source/filter/ww8/wrtww8.cxx b/sw/source/filter/ww8/wrtww8.cxx
index 06f96f2..fdadb13 100644
--- a/sw/source/filter/ww8/wrtww8.cxx
+++ b/sw/source/filter/ww8/wrtww8.cxx
@@ -3330,7 +3330,7 @@ void MSWordExportBase::AddLinkTarget(std::u16string_view rURL)
            {
                pMark = &m_rDoc.GotoTOXMark(*pMark, TOX_SAME_NXT, true);
            }
            if (pMark != &tmp->first)
            if (!SfxPoolItem::areSame(pMark, &tmp->first))
            {
                m_TOXMarkBookmarksByURL.emplace(aURL, name);
                m_TOXMarkBookmarksByTOXMark.emplace(pMark, nameDecoded);
diff --git a/sw/source/filter/xml/xmlfonte.cxx b/sw/source/filter/xml/xmlfonte.cxx
index b8c0f77..c6a9c89 100644
--- a/sw/source/filter/xml/xmlfonte.cxx
+++ b/sw/source/filter/xml/xmlfonte.cxx
@@ -39,6 +39,24 @@ public:

}

namespace
{
sal_Int32 CompareTo(sal_Int32 nA, sal_Int32 nB)
{
    if (nA < nB)
    {
        return -1;
    }

    if (nA > nB)
    {
        return 1;
    }

    return 0;
}
}

SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl(SwXMLExport& _rExport, bool bFontEmbedding)
    : XMLFontAutoStylePool(_rExport, bFontEmbedding)
{
@@ -60,7 +78,34 @@ SwXMLFontAutoStylePool_Impl::SwXMLFontAutoStylePool_Impl(SwXMLExport& _rExport, 
    }

    std::sort(aFonts.begin(), aFonts.end(),
              [](const SvxFontItem* pA, const SvxFontItem* pB) -> bool { return *pA < *pB; });
        [](const SvxFontItem* pA, const SvxFontItem* pB) -> bool
        {
            sal_Int32 nRet = pA->GetFamilyName().compareTo(pB->GetFamilyName());
            if (nRet != 0)
            {
                return nRet < 0;
            }

            nRet = pA->GetStyleName().compareTo(pB->GetStyleName());
            if (nRet != 0)
            {
                return nRet < 0;
            }

            nRet = CompareTo(pA->GetFamily(), pB->GetFamily());
            if (nRet != 0)
            {
                return nRet < 0;
            }

            nRet = CompareTo(pA->GetPitch(), pB->GetPitch());
            if (nRet != 0)
            {
                return nRet < 0;
            }

            return pA->GetCharSet() < pB->GetCharSet();
        });
    for (const auto& pFont : aFonts)
    {
        Add(pFont->GetFamilyName(), pFont->GetStyleName(), pFont->GetFamily(), pFont->GetPitch(),
diff --git a/sw/source/ui/index/swuiidxmrk.cxx b/sw/source/ui/index/swuiidxmrk.cxx
index 52904b7..39443f7 100644
--- a/sw/source/ui/index/swuiidxmrk.cxx
+++ b/sw/source/ui/index/swuiidxmrk.cxx
@@ -287,19 +287,19 @@ void SwIndexMarkPane::InitControls()
        bool bShow = false;

        pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_PRV );
        if( pMoveMark != pMark )
        if (!SfxPoolItem::areSame( pMoveMark, pMark ))
        {
            m_pSh->GotoTOXMark( *pMoveMark, TOX_NXT );
            bShow = true;
        }
        m_xPrevBT->set_sensitive(pMoveMark != pMark);
        m_xPrevBT->set_sensitive(!SfxPoolItem::areSame(pMoveMark, pMark));
        pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_NXT );
        if( pMoveMark != pMark )
        if (!SfxPoolItem::areSame( pMoveMark, pMark ))
        {
            m_pSh->GotoTOXMark( *pMoveMark, TOX_PRV );
            bShow = true;
        }
        m_xNextBT->set_sensitive(pMoveMark != pMark);
        m_xNextBT->set_sensitive(!SfxPoolItem::areSame(pMoveMark, pMark));
        if( bShow )
        {
            m_xPrevBT->show();
@@ -308,19 +308,19 @@ void SwIndexMarkPane::InitControls()
        }

        pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_SAME_PRV );
        if( pMoveMark != pMark )
        if (!SfxPoolItem::areSame( pMoveMark, pMark ))
        {
            m_pSh->GotoTOXMark( *pMoveMark, TOX_SAME_NXT );
            bShow = true;
        }
        m_xPrevSameBT->set_sensitive(pMoveMark != pMark);
        m_xPrevSameBT->set_sensitive(!SfxPoolItem::areSame(pMoveMark, pMark));
        pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_SAME_NXT );
        if( pMoveMark != pMark )
        if (!SfxPoolItem::areSame( pMoveMark, pMark ))
        {
            m_pSh->GotoTOXMark( *pMoveMark, TOX_SAME_PRV );
            bShow = true;
        }
        m_xNextSameBT->set_sensitive(pMoveMark != pMark);
        m_xNextSameBT->set_sensitive(!SfxPoolItem::areSame(pMoveMark, pMark));
        if( bShow )
        {
            m_xNextSameBT->show();
@@ -894,25 +894,25 @@ void SwIndexMarkPane::UpdateDialog()
    if( m_xPrevBT->get_visible() )
    {
        const SwTOXMark* pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_PRV );
        if( pMoveMark != pMark )
        if (!SfxPoolItem::areSame( pMoveMark, pMark ))
            m_pSh->GotoTOXMark( *pMoveMark, TOX_NXT );
        m_xPrevBT->set_sensitive( pMoveMark != pMark );
        m_xPrevBT->set_sensitive( !SfxPoolItem::areSame(pMoveMark, pMark) );
        pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_NXT );
        if( pMoveMark != pMark )
        if (!SfxPoolItem::areSame( pMoveMark, pMark ))
            m_pSh->GotoTOXMark( *pMoveMark, TOX_PRV );
        m_xNextBT->set_sensitive( pMoveMark != pMark );
        m_xNextBT->set_sensitive( !SfxPoolItem::areSame(pMoveMark, pMark) );
    }

    if (m_xPrevSameBT->get_visible())
    {
        const SwTOXMark* pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_SAME_PRV );
        if( pMoveMark != pMark )
        if (!SfxPoolItem::areSame( pMoveMark, pMark ))
            m_pSh->GotoTOXMark( *pMoveMark, TOX_SAME_NXT );
        m_xPrevSameBT->set_sensitive( pMoveMark != pMark );
        m_xPrevSameBT->set_sensitive( !SfxPoolItem::areSame(pMoveMark, pMark) );
        pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_SAME_NXT );
        if( pMoveMark != pMark )
        if (!SfxPoolItem::areSame( pMoveMark, pMark ))
            m_pSh->GotoTOXMark( *pMoveMark, TOX_SAME_PRV );
        m_xNextSameBT->set_sensitive( pMoveMark != pMark );
        m_xNextSameBT->set_sensitive( !SfxPoolItem::areSame(pMoveMark, pMark) );
    }

    const bool bEnable = !m_pSh->HasReadonlySel();
@@ -1013,7 +1013,7 @@ void SwIndexMarkPane::ReInitDlg(SwWrtShell& rWrtShell, SwTOXMark const * pCurTOX
    if(pCurTOXMark)
    {
        for(sal_uInt16 i = 0; i < m_pTOXMgr->GetTOXMarkCount(); i++)
            if(m_pTOXMgr->GetTOXMark(i) == pCurTOXMark)
            if (SfxPoolItem::areSame(m_pTOXMgr->GetTOXMark(i), pCurTOXMark))
            {
                m_pTOXMgr->SetCurTOXMark(i);
                break;
diff --git a/sw/source/uibase/index/toxmgr.cxx b/sw/source/uibase/index/toxmgr.cxx
index 5fc78fc..8b8ff6d 100644
--- a/sw/source/uibase/index/toxmgr.cxx
+++ b/sw/source/uibase/index/toxmgr.cxx
@@ -47,7 +47,7 @@ void SwTOXMgr::DeleteTOXMark()
    if( m_pCurTOXMark )
    {
        pNext = const_cast<SwTOXMark*>(&m_pSh->GotoTOXMark( *m_pCurTOXMark, TOX_NXT ));
        if( pNext == m_pCurTOXMark )
        if (SfxPoolItem::areSame( pNext, m_pCurTOXMark ))
            pNext = nullptr;

        m_pSh->DeleteTOXMark( m_pCurTOXMark );
diff --git a/sw/source/uibase/shells/frmsh.cxx b/sw/source/uibase/shells/frmsh.cxx
index 65c41bec..0976b6c 100644
--- a/sw/source/uibase/shells/frmsh.cxx
+++ b/sw/source/uibase/shells/frmsh.cxx
@@ -1093,7 +1093,7 @@ void SwFrameShell::ExecFrameStyle(SfxRequest const & rReq)
    rSh.GetFlyFrameAttr( aFrameSet );
    const SvxBoxItem& rBoxItem = aFrameSet.Get(RES_BOX);

    if (pPoolBoxItem == &rBoxItem)
    if (SfxPoolItem::areSame(pPoolBoxItem, &rBoxItem))
        bDefault = true;

    std::unique_ptr<SvxBoxItem> aBoxItem(rBoxItem.Clone());
diff --git a/sw/source/uibase/uiview/view2.cxx b/sw/source/uibase/uiview/view2.cxx
index a6aae01..6cb3aee 100644
--- a/sw/source/uibase/uiview/view2.cxx
+++ b/sw/source/uibase/uiview/view2.cxx
@@ -2538,7 +2538,8 @@ static auto JumpToTOXMark(SwWrtShell & rSh, std::u16string_view aName) -> bool
    }
    SwTOXMark const* pMark(&tmp->first);
    // hack: check first if one exists
    if (&tmp->first != &rSh.GetDoc()->GotoTOXMark(tmp->first, TOX_SAME_NXT, rSh.IsReadOnlyAvailable()))
    // need simple ptr control, else UnitTest CppunitTest_sw_uiwriter3 fails
    if (!areSfxPoolItemPtrsEqual(&tmp->first, &rSh.GetDoc()->GotoTOXMark(tmp->first, TOX_SAME_NXT, rSh.IsReadOnlyAvailable())))
    {
        for (sal_Int32 i = 0; i < tmp->second; ++i)
        {
diff --git a/sw/source/uibase/utlui/content.cxx b/sw/source/uibase/utlui/content.cxx
index 3a4322a..4c126fb 100644
--- a/sw/source/uibase/utlui/content.cxx
+++ b/sw/source/uibase/utlui/content.cxx
@@ -5262,7 +5262,7 @@ void SwContentTree::EditEntry(const weld::TreeIter& rEntry, EditEntryMode nMode)
            if(nMode == EditEntryMode::DELETE)
            {
                const OUString& rName = pCnt->GetName();
                for (SfxPoolItem* pItem :
                for (const SfxPoolItem* pItem :
                     m_pActiveShell->GetDoc()->GetAttrPool().GetItemSurrogates(RES_TXTATR_REFMARK))
                {
                    assert(dynamic_cast<const SwFormatRefMark*>(pItem));
diff --git a/vcl/source/app/svapp.cxx b/vcl/source/app/svapp.cxx
index 269077d..44dfa0a 100644
--- a/vcl/source/app/svapp.cxx
+++ b/vcl/source/app/svapp.cxx
@@ -78,6 +78,7 @@
#ifdef DBG_UTIL
#include <svl/poolitem.hxx>
#include <svl/itemset.hxx>
#include <svl/itempool.hxx>
#endif

#include <cassert>
@@ -192,12 +193,20 @@ Application::~Application()
    // on amounts of SfxPoolItems used during office usage and to be able to
    // detect if an error in future changes may lead to memory losses - these
    // would show in dramatically higher numbers then immediately
    SAL_WARN("vcl", "ITEM: " << getAllocatedSfxPoolItemCount() << " SfxPoolItems still allocated at shutdown");
    SAL_WARN("vcl", "ITEM: " << getUsedSfxPoolItemCount() << " SfxPoolItems were incarnated during office usage");
    SAL_INFO("vcl.items", "ITEM: " << getAllocatedSfxPoolItemCount() << " SfxPoolItems still allocated at shutdown");
    SAL_INFO("vcl.items", "ITEM: " << getUsedSfxPoolItemCount() << " SfxPoolItems were incarnated during runtime");

    // Same mechanism for SfxItemSet(s)
    SAL_WARN("vcl", "ITEM: " << getAllocatedSfxItemSetCount() << " SfxItemSets still allocated at shutdown");
    SAL_WARN("vcl", "ITEM: " << getUsedSfxItemSetCount() << " SfxItemSets were incarnated during office usage");
    SAL_INFO("vcl.items", "ITEM: " << getAllocatedSfxItemSetCount() << " SfxItemSets still allocated at shutdown");
    SAL_INFO("vcl.items", "ITEM: " << getUsedSfxItemSetCount() << " SfxItemSets were incarnated during runtime");

    // Same mechanism for SfxPoolItem(s)directly put to a Pool
    SAL_INFO("vcl.items", "ITEM: " << getRemainingDirectlyPooledSfxPoolItemCount() << " SfxPoolItems still directly put in Pool at shutdown (deleted @Pool destruction)");
    SAL_INFO("vcl.items", "ITEM: " << getAllDirectlyPooledSfxPoolItemCount() << " SfxPoolItems directly put in Pool");

    // Additional call to list still incarnated SfxPoolItems (under 'svl.items')
    listAllocatedSfxPoolItems();

#endif
}