related tdf#158031 editeng: GetFieldAtSel...(+look before cursor)

Nearly a No-Functional-Change, but not quite.
For practical and intentional purposes, it can be considered NFC.

Although I didn't find an actual case where it happened,
a code read says SelectFieldAtCursor COULD select a non-field.
It assumed that previous code had already identified that there
must be a field here.

Well, I want to extend GetFieldAtSelection to check backwards
to solve bug 158031 anyway, so I might as well "fix"
this assumption to only select a valid field.

This function REALLY depends on
GetFieldAtSelection working properly.
So, I put some asserts in to ensure that stays true.

Change-Id: Ie22945a418497511501b04df5e17071d977cbd5b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158855
Tested-by: Jenkins
Reviewed-by: Justin Luth <jluth@mail.com>
diff --git a/editeng/source/editeng/editview.cxx b/editeng/source/editeng/editview.cxx
index d73cb24..bfa98d1 100644
--- a/editeng/source/editeng/editview.cxx
+++ b/editeng/source/editeng/editview.cxx
@@ -1344,7 +1344,16 @@ const SvxFieldItem* EditView::GetFieldUnderMousePointer( sal_Int32& nPara, sal_I
    return GetField( aPos, &nPara, &nPos );
}

const SvxFieldItem* EditView::GetFieldAtSelection() const
const SvxFieldItem* EditView::GetFieldAtSelection(bool bAlsoCheckBeforeCursor) const
{
    bool* pIsBeforeCursor = bAlsoCheckBeforeCursor ? &bAlsoCheckBeforeCursor : nullptr;
    return GetFieldAtSelection(pIsBeforeCursor);
}

// If pIsBeforeCursor != nullptr, the position before the cursor will also be checked for a field
// and pIsBeforeCursor will return true if that fallback field is returned.
// If no field is returned, the value in pIsBeforeCursor is meaningless.
const SvxFieldItem* EditView::GetFieldAtSelection(bool* pIsBeforeCursor) const
{
    // a field is a dummy character - so it cannot span nodes or be a selection larger than 1
    EditSelection aSel( pImpEditView->GetEditSelection() );
@@ -1361,6 +1370,13 @@ const SvxFieldItem* EditView::GetFieldAtSelection() const

    // Only when cursor is in font of field, no selection,
    // or only selecting field
    bool bAlsoCheckBeforeCursor = false;
    if (pIsBeforeCursor)
    {
        *pIsBeforeCursor = false;
        bAlsoCheckBeforeCursor = nMaxIndex == nMinIndex;
    }
    const SvxFieldItem* pFoundBeforeCursor = nullptr;
    const CharAttribList::AttribsType& rAttrs = aSel.Min().GetNode()->GetCharAttribs().GetAttribs();
    for (const auto& rAttr: rAttrs)
    {
@@ -1369,34 +1385,43 @@ const SvxFieldItem* EditView::GetFieldAtSelection() const
            DBG_ASSERT(dynamic_cast<const SvxFieldItem*>(rAttr->GetItem()), "No FieldItem...");
            if (rAttr->GetStart() == nMinIndex)
                return static_cast<const SvxFieldItem*>(rAttr->GetItem());

            // perhaps the cursor is behind the field?
            if (nMinIndex && rAttr->GetStart() == nMinIndex - 1)
                pFoundBeforeCursor = static_cast<const SvxFieldItem*>(rAttr->GetItem());
        }
    }
    if (bAlsoCheckBeforeCursor)
    {
        *pIsBeforeCursor = /*(bool)*/pFoundBeforeCursor;
        return pFoundBeforeCursor;
    }
    return nullptr;
}

void EditView::SelectFieldAtCursor()
{
    const SvxFieldItem* pFieldItem = GetFieldAtSelection();
    if (pFieldItem)
    {
        // Make sure the whole field is selected
        ESelection aSel = GetSelection();
        if (aSel.nStartPos == aSel.nEndPos)
        {
            aSel.nEndPos++;
            SetSelection(aSel);
        }
    }
    bool bIsBeforeCursor = false;
    const SvxFieldItem* pFieldItem = GetFieldAtSelection(&bIsBeforeCursor);
    if (!pFieldItem)
        return;

    // Make sure the whole field is selected
    // A field is represented by a dummy character - so it cannot be a selection larger than 1
    ESelection aSel = GetSelection();
    if (aSel.nStartPos == aSel.nEndPos) // not yet selected
    {
        // Cursor probably behind the field - extend selection to select the field
        ESelection aSel = GetSelection();
        if (aSel.nStartPos > 0 && aSel.nStartPos == aSel.nEndPos)
        if (bIsBeforeCursor)
        {
            aSel.nStartPos--;
            SetSelection(aSel);
            assert (aSel.nStartPos);
            --aSel.nStartPos;
        }
        else
            aSel.nEndPos++;
        SetSelection(aSel);
    }
    else
        assert(std::abs(aSel.nStartPos - aSel.nEndPos) == 1);
}

const SvxFieldData* EditView::GetFieldAtCursor() const
diff --git a/include/editeng/editview.hxx b/include/editeng/editview.hxx
index 48019e3..4c18ac2 100644
--- a/include/editeng/editview.hxx
+++ b/include/editeng/editview.hxx
@@ -329,7 +329,10 @@ public:
    const SvxFieldItem* GetFieldUnderMousePointer( sal_Int32& nPara, sal_Int32& nPos ) const;
    const SvxFieldItem* GetField( const Point& rPos, sal_Int32* pnPara = nullptr, sal_Int32* pnPos = nullptr ) const;

    const SvxFieldItem* GetFieldAtSelection() const;
    /// return the selected field or the field immediately after (or before) the current cursor
    const SvxFieldItem* GetFieldAtSelection(bool bAlsoCheckBeforeCursor = false) const;
    const SvxFieldItem* GetFieldAtSelection(bool* pIsBeforeCursor) const;

    /// Select and return the field at the current cursor position
    const SvxFieldData* GetFieldAtCursor() const;
    void SelectFieldAtCursor();