tdf#158773 reduce cost of ContentInfo::GetText

The specific path that is showing up on the perf profile is

SdrTextObj::HasText -> EditTextObjectImpl::GetText ->
ContentInfo::GetText

Reduce the cost by 10% there by adding a method to check if we have text, and
avoid the cost of constructing an OUString from an svl::SharedString.

Also make use of the new method in places.

Change-Id: Ibc2e0f61c4a2a6c33eea7f2cce09d692d82fd2b2
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164449
Tested-by: Noel Grandin <noel.grandin@collabora.co.uk>
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/editeng/source/editeng/editobj.cxx b/editeng/source/editeng/editobj.cxx
index 762cac1..9b17e43 100644
--- a/editeng/source/editeng/editobj.cxx
+++ b/editeng/source/editeng/editobj.cxx
@@ -126,6 +126,12 @@ OUString ContentInfo::GetText() const
    return OUString(p);
}

sal_Int32 ContentInfo::GetTextLen() const
{
    const rtl_uString* p = maText.getData();
    return p->length;
}

void ContentInfo::SetText( const OUString& rStr )
{
    maText = svl::SharedString(rStr.pData, nullptr);
@@ -392,6 +398,14 @@ OUString EditTextObjectImpl::GetText(sal_Int32 nPara) const
    return maContents[nPara]->GetText();
}

sal_Int32 EditTextObjectImpl::GetTextLen(sal_Int32 nPara ) const
{
    if (nPara < 0 || o3tl::make_unsigned(nPara) >= maContents.size())
        return 0;

    return maContents[nPara]->GetTextLen();
}

void EditTextObjectImpl::ClearPortionInfo()
{
    mpPortionInfo.reset();
diff --git a/editeng/source/editeng/editobj2.hxx b/editeng/source/editeng/editobj2.hxx
index fd1f143..4392022b 100644
--- a/editeng/source/editeng/editobj2.hxx
+++ b/editeng/source/editeng/editobj2.hxx
@@ -140,6 +140,7 @@ public:
    const svl::SharedString& GetSharedString() const { return maText;}
    OUString GetText() const;
    void SetText( const OUString& rStr );
    sal_Int32 GetTextLen() const;

    void dumpAsXml(xmlTextWriterPtr pWriter) const;

@@ -225,6 +226,7 @@ public:

    virtual sal_Int32 GetParagraphCount() const override;
    virtual OUString GetText(sal_Int32 nParagraph) const override;
    virtual sal_Int32 GetTextLen(sal_Int32 nParagraph) const override;

    virtual void ClearPortionInfo() override;

diff --git a/editeng/source/outliner/overflowingtxt.cxx b/editeng/source/outliner/overflowingtxt.cxx
index 8346f43..0a17cd6 100644
--- a/editeng/source/outliner/overflowingtxt.cxx
+++ b/editeng/source/outliner/overflowingtxt.cxx
@@ -45,7 +45,7 @@ std::optional<OutlinerParaObject> TextChainingUtils::JuxtaposeParaObject(
    // Special case: if only empty text remove it at the end
    bool bOnlyOneEmptyPara = !pNextPObj ||
                             (pOutl->GetParagraphCount() == 1 &&
                              pNextPObj->GetTextObject().GetText(0).isEmpty());
                              !pNextPObj->GetTextObject().HasText(0));

    EditEngine &rEditEngine = const_cast<EditEngine &>(pOutl->GetEditEngine());

diff --git a/include/editeng/editobj.hxx b/include/editeng/editobj.hxx
index 5badaf8..b78b1a91 100644
--- a/include/editeng/editobj.hxx
+++ b/include/editeng/editobj.hxx
@@ -87,6 +87,10 @@ public:

    virtual OUString GetText(sal_Int32 nPara) const = 0;

    virtual sal_Int32 GetTextLen(sal_Int32 nPara) const = 0;

    bool HasText(sal_Int32 nPara) const { return GetTextLen(nPara) > 0; }

    virtual void ClearPortionInfo() = 0;

    virtual bool HasOnlineSpellErrors() const = 0;
diff --git a/sc/source/filter/xcl97/xcl97rec.cxx b/sc/source/filter/xcl97/xcl97rec.cxx
index 65facba..8abe7dc 100644
--- a/sc/source/filter/xcl97/xcl97rec.cxx
+++ b/sc/source/filter/xcl97/xcl97rec.cxx
@@ -921,8 +921,7 @@ XclTxo::XclTxo( const XclExpRoot& rRoot, const EditTextObject& rEditObj, SdrObje
    // Excel has one alignment per NoteObject while Calc supports
    // one alignment per paragraph - use the first paragraph
    // alignment (if set) as our overall alignment.
    OUString aParaText( rEditObj.GetText( 0 ) );
    if( !aParaText.isEmpty() )
    if( rEditObj.HasText( 0 ) )
    {
        const SfxItemSet& aSet( rEditObj.GetParaAttribs( 0));
        if( const SvxAdjustItem* pItem = aSet.GetItemIfSet( EE_PARA_JUST ) )
diff --git a/sc/source/ui/Accessibility/AccessiblePageHeader.cxx b/sc/source/ui/Accessibility/AccessiblePageHeader.cxx
index a790172..1c82cfa 100644
--- a/sc/source/ui/Accessibility/AccessiblePageHeader.cxx
+++ b/sc/source/ui/Accessibility/AccessiblePageHeader.cxx
@@ -348,7 +348,7 @@ bool ScAccessiblePageHeader::IsDefunc( sal_Int64 nParentStates )

void ScAccessiblePageHeader::AddChild(const EditTextObject* pArea, sal_uInt32 nIndex, SvxAdjust eAdjust)
{
    if (pArea && (!pArea->GetText(0).isEmpty() || (pArea->GetParagraphCount() > 1)))
    if (pArea && ((pArea->GetParagraphCount() > 1) || pArea->HasText(0)))
    {
        if (maAreas[nIndex].is())
        {
diff --git a/sc/source/ui/view/viewfunc.cxx b/sc/source/ui/view/viewfunc.cxx
index 21c2a9c..e4153cb 100644
--- a/sc/source/ui/view/viewfunc.cxx
+++ b/sc/source/ui/view/viewfunc.cxx
@@ -921,7 +921,7 @@ void ScViewFunc::EnterData( SCCOL nCol, SCROW nRow, SCTAB nTab,
            pDocSh->UpdateOle(GetViewData());

            bool bIsEmpty = rData.GetParagraphCount() == 0
                || (rData.GetParagraphCount() == 1 && rData.GetText(0).isEmpty());
                || (rData.GetParagraphCount() == 1 && !rData.HasText(0));
            const OUString aType(bIsEmpty ? u"delete-content" : u"cell-change");
            HelperNotifyChanges::NotifyIfChangesListeners(*pDocSh, rMark, nCol, nRow, aType);

diff --git a/sd/source/filter/ppt/pptinanimations.cxx b/sd/source/filter/ppt/pptinanimations.cxx
index ffe081e..76f9310 100644
--- a/sd/source/filter/ppt/pptinanimations.cxx
+++ b/sd/source/filter/ppt/pptinanimations.cxx
@@ -2523,7 +2523,7 @@ void AnimationImporter::importTargetElementContainer( const Atom* pAtom, Any& rT

                    while( (nPara < nParaCount) && (begin > 0) )
                    {
                        sal_Int32 nParaLength = rEditTextObject.GetText( nPara ).getLength() + 1;
                        sal_Int32 nParaLength = rEditTextObject.GetTextLen( nPara ) + 1;
                        begin -= nParaLength;
                        end -= nParaLength;
                        nPara++;
diff --git a/svx/source/svdraw/svdotxat.cxx b/svx/source/svdraw/svdotxat.cxx
index 4957a4f..6b39887 100644
--- a/svx/source/svdraw/svdotxat.cxx
+++ b/svx/source/svdraw/svdotxat.cxx
@@ -424,17 +424,16 @@ bool SdrTextObj::HasText() const

    OutlinerParaObject* pOPO = GetOutlinerParaObject();

    bool bHasText = false;
    if( pOPO )
    {
        const EditTextObject& rETO = pOPO->GetTextObject();
        sal_Int32 nParaCount = rETO.GetParagraphCount();
    if( !pOPO )
        return false;

        if( nParaCount > 0 )
            bHasText = (nParaCount > 1) || (!rETO.GetText( 0 ).isEmpty());
    }

    return bHasText;
    const EditTextObject& rETO = pOPO->GetTextObject();
    sal_Int32 nParaCount = rETO.GetParagraphCount();
    if( nParaCount == 0 )
        return false;
    if( nParaCount > 1 )
        return true;
    return rETO.HasText( 0 );
}

void SdrTextObj::AppendFamilyToStyleName(OUString& styleName, SfxStyleFamily family)
diff --git a/svx/source/table/cell.cxx b/svx/source/table/cell.cxx
index a7dc739..0c4c4ba 100644
--- a/svx/source/table/cell.cxx
+++ b/svx/source/table/cell.cxx
@@ -563,7 +563,7 @@ bool Cell::hasText() const
        {
            if( rTextObj.GetParagraphCount() == 1 )
            {
                if( rTextObj.GetText(0).isEmpty() )
                if( !rTextObj.HasText(0) )
                    return false;
            }
            return true;
diff --git a/sw/source/uibase/docvw/AnnotationWin.cxx b/sw/source/uibase/docvw/AnnotationWin.cxx
index 714c141..409b8be 100644
--- a/sw/source/uibase/docvw/AnnotationWin.cxx
+++ b/sw/source/uibase/docvw/AnnotationWin.cxx
@@ -417,7 +417,7 @@ void SwAnnotationWin::InitAnswer(OutlinerParaObject const & rText)

    // insert old, selected text or "..."
    // TODO: iterate over all paragraphs, not only first one to find out if it is empty
    if (!rText.GetTextObject().GetText(0).isEmpty())
    if (rText.GetTextObject().HasText(0))
        GetOutlinerView()->GetEditView().InsertText(rText.GetTextObject());
    else
        GetOutlinerView()->InsertText("...");