office-gobmx/include/editeng/brushitem.hxx
Armin Le Grand (allotropia) 063781f4a9 tdf#158605 Add global SfxPoolItem re-use
The task shows that the commit including the Item
paradigm change has follow-ups: It now does no
longer try to share Items as much as possible
(detailed reasons in that commit). Mainly for speed
reasons since that sharing was done before by
(mostly) linearly searching in existing instances
registered at one Pool, using the operator== of the
SfxPoolItems. That costs runtime.

There is somewhere a sweet-spot between memory and
runtime: the number of Items allocated and the time
spent to share them more effectively. This task shows
- despite being a non-real-world document - that
for extremes like this putting work in sharing is
still needed.

But there are possibilities to combine both: If we
can implement solutions that do not need much time
to ideintify an aleady existing instance we will get
the best of both worlds.

As explained already in that change, if we would
need that again, then on a better base. Thus I drove
forward ITEM changes to a state where we are now able
to share Items globally in the office - not per pool
but for all ItemSets/ItemHolders and thus all Apps/
Models/opened documents.

NOTE: This currently needs to include the WhichID
that is included in the Item, so cannot share pure
Item-data (as the old usage did too). This does not
need to stay that way: If you think about it, the
association between WhichID and Pool/Holder is
defined in Pool/Holder, so theoretically the Item
does not need to contain the WhichID. This will
be hard to do due too many places in the code that
use the WhichID stored at the Item.

To support that I added an ItemInstanceManager with
a simple interface (find/add/remove) and it's usage
in the two central Item-existance managing methods
implCreateItemEntry/implCleanupItemEntry. The
interface is pure virtual and all methods private,
only the mentioned managing methods are allowed to
access these. Also added a virtual method to
SfxPoolItem called getItemInstanceManager() that
can be implemented by Items that want to support
that.

Also added a default implementation of
ItemInstanceManager called DefaultItemInstanceManager
that uses linear search using operator== from the
Item that can be used/added to every Item easily.
It works for all Items and does in principle what
the former implementation does. It is intended as
simple/fast fallback.

I also added a statistic element to measure the most
used non-RefCounted Items on an Office-run, this
will be printed at office shutdown using SAL_LOG
and the 'svl.items' flag.

I then checked all Items that were used in this
error/bug scenario that used an extensive number
of incarnations and added an ItemInstanceManager
for these.

For SvxFontItem I added one that creates a hash and
thus needs not to search for instances at all, with
the caveat that the WhichID needs to be included.
Thus the hash is not at the Item, but only in the
ItemInstanceManager implementation.

For SfxBoolItem I implemented one that hashes using
the WhichID and holding both possible states in an
associated std::pair, true and false, thus the
SfxBoolItem is identified fast and only two instances
per WhichID exist (when used in Pool/Holder).

For 11 other Items I just added using the standard
implementation, DefaultItemInstanceManager. Of
course the more we optimize the better it will get.

For all Items where I added that mechanism I also
added ASSERT_CHANGE_REFCOUNTED_ITEM to all write
calls/methods for that Item. It asserts when the
RefCounted Item is to be changed. This should be
done in all write accesses to Items, but we have
ca. 500 derivations.
NOTE: There was *one* place I found where that
was already done -> was alredy seen as problem,
but not really adressed.

Despite this example file is not representative,
it is still a start to init this new instance
re-use of Items.

I am already thinking about doing that globally,
depending on the usage number (maybe combined with
sizeof(item)). There is no argument to not even
change strategy at runtime when a specific number
of incarnations of one Item derivation is reached,
but this is not part of this fix.

Change-Id: Ie56cf40e0341f98dcbf29cf5c06368316829415e
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/162402
Tested-by: Jenkins
Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
2024-01-23 18:56:12 +01:00

144 lines
5.4 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#pragma once
#include <tools/color.hxx>
#include <svl/poolitem.hxx>
#include <editeng/editengdllapi.h>
#include <memory>
#include <docmodel/color/ComplexColor.hxx>
class Graphic;
class GraphicObject;
constexpr sal_uInt16 BRUSH_GRAPHIC_VERSION = 0x0001;
enum SvxGraphicPosition
{
GPOS_NONE,
GPOS_LT, GPOS_MT, GPOS_RT,
GPOS_LM, GPOS_MM, GPOS_RM,
GPOS_LB, GPOS_MB, GPOS_RB,
GPOS_AREA, GPOS_TILED
};
class EDITENG_DLLPUBLIC SvxBrushItem final : public SfxPoolItem
{
Color aColor;
model::ComplexColor maComplexColor;
Color aFilterColor;
sal_Int32 nShadingValue;
mutable std::unique_ptr<GraphicObject> xGraphicObject;
sal_Int8 nGraphicTransparency; //contains a percentage value which is
//copied to the GraphicObject when necessary
OUString maStrLink;
OUString maStrFilter;
SvxGraphicPosition eGraphicPos;
mutable bool bLoadAgain;
void ApplyGraphicTransparency_Impl();
protected:
virtual ItemInstanceManager* getItemInstanceManager() const override;
public:
static SfxPoolItem* CreateDefault();
explicit SvxBrushItem( sal_uInt16 nWhich );
SvxBrushItem(Color const& rColor, sal_uInt16 nWhich);
SvxBrushItem(Color const& rColor, model::ComplexColor const& rComplexColor, sal_uInt16 nWhich);
SvxBrushItem( const Graphic& rGraphic,
SvxGraphicPosition ePos, sal_uInt16 nWhich );
SvxBrushItem( const GraphicObject& rGraphicObj,
SvxGraphicPosition ePos, sal_uInt16 nWhich );
SvxBrushItem( OUString rLink, OUString aFilter,
SvxGraphicPosition ePos, sal_uInt16 nWhich );
SvxBrushItem( const SvxBrushItem& );
SvxBrushItem(SvxBrushItem&&);
virtual ~SvxBrushItem() override;
public:
// check if it's used
bool isUsed() const;
virtual bool GetPresentation( SfxItemPresentation ePres,
MapUnit eCoreMetric,
MapUnit ePresMetric,
OUString &rText, const IntlWrapper& ) const override;
virtual bool operator==( const SfxPoolItem& ) 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;
virtual SvxBrushItem* Clone( SfxItemPool *pPool = nullptr ) const override;
const Color& GetColor() const { return aColor; }
Color& GetColor() { return aColor; }
void SetColor( const Color& rCol)
{
ASSERT_CHANGE_REFCOUNTED_ITEM;
aColor = rCol;
}
const model::ComplexColor& getComplexColor() const
{
auto pUnConst = const_cast<SvxBrushItem*>(this);
pUnConst->maComplexColor.setFinalColor(GetColor());
return maComplexColor;
}
void setComplexColor(model::ComplexColor const& rComplexColor)
{
ASSERT_CHANGE_REFCOUNTED_ITEM;
maComplexColor = rComplexColor;
}
const Color& GetFiltColor() const { return aFilterColor; }
void SetFiltColor( const Color& rCol)
{
ASSERT_CHANGE_REFCOUNTED_ITEM;
aFilterColor = rCol;
}
SvxGraphicPosition GetGraphicPos() const { return eGraphicPos; }
sal_Int32 GetShadingValue() const { return nShadingValue; }
const Graphic* GetGraphic(OUString const & referer = OUString()/*TODO*/) const;
const GraphicObject* GetGraphicObject(OUString const & referer = OUString()/*TODO*/) const;
const OUString& GetGraphicLink() const { return maStrLink; }
const OUString& GetGraphicFilter() const { return maStrFilter; }
// get graphic transparency in percent
sal_Int8 getGraphicTransparency() const { return nGraphicTransparency; }
void setGraphicTransparency(sal_Int8 nNew);
void SetGraphicPos( SvxGraphicPosition eNew );
void SetGraphic( const Graphic& rNew );
void SetGraphicObject( const GraphicObject& rNewObj );
void SetGraphicLink( const OUString& rNew );
void SetGraphicFilter( const OUString& rNew );
static sal_Int8 TransparencyToPercent(sal_Int32 nTrans);
void dumpAsXml(xmlTextWriterPtr pWriter) const override;
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */