First step toward showing mis-spelled words without modifying cells.

There are still tons of problems to fix.

Change-Id: Icae6e3d2c9b8b2266724d8d068abbab8acae96da
diff --git a/editeng/source/editeng/editeng.cxx b/editeng/source/editeng/editeng.cxx
index 95a7ac2..4e34071 100644
--- a/editeng/source/editeng/editeng.cxx
+++ b/editeng/source/editeng/editeng.cxx
@@ -2284,6 +2284,16 @@ void EditEngine::SetHyphenator( Reference< XHyphenator > & xHyph )
    pImpEditEngine->SetHyphenator( xHyph );
}

void EditEngine::GetAllMisspellRanges( std::vector<editeng::MisspellRanges>& rRanges ) const
{
    pImpEditEngine->GetAllMisspellRanges(rRanges);
}

void EditEngine::SetAllMisspellRanges( const std::vector<editeng::MisspellRanges>& rRanges )
{
    pImpEditEngine->SetAllMisspellRanges(rRanges);
}

void EditEngine::SetForbiddenCharsTable( rtl::Reference<SvxForbiddenCharactersTable> xForbiddenChars )
{
    DBG_CHKTHIS( EditEngine, 0 );
diff --git a/editeng/source/editeng/edtspell.cxx b/editeng/source/editeng/edtspell.cxx
index 6d7bcd1..6c2fdf7 100644
--- a/editeng/source/editeng/edtspell.cxx
+++ b/editeng/source/editeng/edtspell.cxx
@@ -207,6 +207,16 @@ WrongList::WrongList(const WrongList& r) :

WrongList::~WrongList() {}

const std::vector<editeng::MisspellRange>& WrongList::GetRanges() const
{
    return maRanges;
}

void WrongList::SetRanges( const std::vector<editeng::MisspellRange>& rRanges )
{
    maRanges = rRanges;
}

bool WrongList::IsValid() const
{
    return mnInvalidStart == Valid;
diff --git a/editeng/source/editeng/edtspell.hxx b/editeng/source/editeng/edtspell.hxx
index c79c2ac..8049b5f 100644
--- a/editeng/source/editeng/edtspell.hxx
+++ b/editeng/source/editeng/edtspell.hxx
@@ -86,6 +86,9 @@ public:
    WrongList(const WrongList& r);
    ~WrongList();

    const std::vector<editeng::MisspellRange>& GetRanges() const;
    void SetRanges( const std::vector<editeng::MisspellRange>& rRanges );

    bool IsValid() const;
    void SetValid();
    void SetInvalidRange( size_t nStart, size_t nEnd );
diff --git a/editeng/source/editeng/impedit.hxx b/editeng/source/editeng/impedit.hxx
index f15f01a..b62bc02 100644
--- a/editeng/source/editeng/impedit.hxx
+++ b/editeng/source/editeng/impedit.hxx
@@ -100,6 +100,10 @@ namespace svtools {
    class ColorConfig;
}

namespace editeng {
    struct MisspellRanges;
}

struct DragAndDropInfo
{
    Rectangle           aCurCursor;
@@ -886,6 +890,10 @@ public:
    void                SetHyphenator( ::com::sun::star::uno::Reference<
                            ::com::sun::star::linguistic2::XHyphenator >  &xHyph )
                            { xHyphenator = xHyph; }

    void GetAllMisspellRanges( std::vector<editeng::MisspellRanges>& rRanges ) const;
    void SetAllMisspellRanges( const std::vector<editeng::MisspellRanges>& rRanges );

    SpellInfo*          GetSpellInfo() const { return pSpellInfo; }

    void                SetDefaultLanguage( LanguageType eLang ) { eDefLanguage = eLang; }
diff --git a/editeng/source/editeng/impedit4.cxx b/editeng/source/editeng/impedit4.cxx
index 734a83c..99a9101 100644
--- a/editeng/source/editeng/impedit4.cxx
+++ b/editeng/source/editeng/impedit4.cxx
@@ -1391,6 +1391,40 @@ EditSelection ImpEditEngine::InsertTextObject( const EditTextObject& rTextObject
    return aSel;
}

void ImpEditEngine::GetAllMisspellRanges( std::vector<editeng::MisspellRanges>& rRanges ) const
{
    std::vector<editeng::MisspellRanges> aRanges;
    const EditDoc& rDoc = GetEditDoc();
    for (sal_Int32 i = 0, n = rDoc.Count(); i < n; ++i)
    {
        const ContentNode* pNode = rDoc.GetObject(i);
        const WrongList* pWrongList = pNode->GetWrongList();
        if (!pWrongList)
            continue;

        aRanges.push_back(editeng::MisspellRanges(i, pWrongList->GetRanges()));
    }

    aRanges.swap(rRanges);
}

void ImpEditEngine::SetAllMisspellRanges( const std::vector<editeng::MisspellRanges>& rRanges )
{
    EditDoc& rDoc = GetEditDoc();
    std::vector<editeng::MisspellRanges>::const_iterator it = rRanges.begin(), itEnd = rRanges.end();
    for (; it != itEnd; ++it)
    {
        const editeng::MisspellRanges& rParaRanges = *it;
        ContentNode* pNode = rDoc.GetObject(rParaRanges.mnParagraph);
        if (!pNode)
            continue;

        pNode->CreateWrongList();
        WrongList* pWrongList = pNode->GetWrongList();
        pWrongList->SetRanges(rParaRanges.maRanges);
    }
}

LanguageType ImpEditEngine::GetLanguage( const EditPaM& rPaM, sal_uInt16* pEndPos ) const
{
    short nScriptType = GetScriptType( rPaM, pEndPos ); // pEndPos will be valid now, pointing to ScriptChange or NodeLen
diff --git a/editeng/source/editeng/misspellrange.cxx b/editeng/source/editeng/misspellrange.cxx
index 0136705..980a559 100644
--- a/editeng/source/editeng/misspellrange.cxx
+++ b/editeng/source/editeng/misspellrange.cxx
@@ -14,6 +14,9 @@ namespace editeng {
MisspellRange::MisspellRange() : mnStart(0), mnEnd(0) {}
MisspellRange::MisspellRange(size_t nStart, size_t nEnd) : mnStart(nStart), mnEnd(nEnd) {}

MisspellRanges::MisspellRanges(size_t nParagraph, const std::vector<MisspellRange>& rRanges) :
    mnParagraph(nParagraph), maRanges(rRanges) {}

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/editeng/editeng.hxx b/include/editeng/editeng.hxx
index 6fd91a4..7545317 100644
--- a/include/editeng/editeng.hxx
+++ b/include/editeng/editeng.hxx
@@ -55,6 +55,9 @@ typedef std::vector<SpellPortion> SpellPortions;

namespace svl { class IUndoManager; }
namespace basegfx { class B2DPolyPolygon; }
namespace editeng {
    struct MisspellRanges;
}

class ImpEditEngine;
class EditView;
@@ -398,6 +401,9 @@ public:
    void            SetHyphenator( ::com::sun::star::uno::Reference<
                            ::com::sun::star::linguistic2::XHyphenator >& xHyph );

    void GetAllMisspellRanges( std::vector<editeng::MisspellRanges>& rRanges ) const;
    void SetAllMisspellRanges( const std::vector<editeng::MisspellRanges>& rRanges );

    void            SetForbiddenCharsTable( rtl::Reference<SvxForbiddenCharactersTable> xForbiddenChars );

    void            SetDefaultLanguage( LanguageType eLang );
diff --git a/include/editeng/misspellrange.hxx b/include/editeng/misspellrange.hxx
index 103b58a..4b34e22 100644
--- a/include/editeng/misspellrange.hxx
+++ b/include/editeng/misspellrange.hxx
@@ -12,6 +12,8 @@

#include "editeng/editengdllapi.h"

#include <vector>

namespace editeng {

struct EDITENG_DLLPUBLIC MisspellRange
@@ -23,6 +25,14 @@ struct EDITENG_DLLPUBLIC MisspellRange
    MisspellRange(size_t nStart, size_t nEnd);
};

struct EDITENG_DLLPUBLIC MisspellRanges
{
    size_t mnParagraph;
    std::vector<MisspellRange> maRanges;

    MisspellRanges(size_t nParagraph, const std::vector<MisspellRange>& rRanges);
};

}

#endif
diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 1ef9a82..3c06eaf 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -592,6 +592,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
	sc/source/ui/view/selectionstate \
	sc/source/ui/view/spelldialog \
	sc/source/ui/view/spelleng \
	sc/source/ui/view/spellcheckcontext \
	sc/source/ui/view/tabcont \
	sc/source/ui/view/tabsplit \
	sc/source/ui/view/tabview \
diff --git a/sc/inc/spellcheckcontext.hxx b/sc/inc/spellcheckcontext.hxx
new file mode 100644
index 0000000..c92cee4
--- /dev/null
+++ b/sc/inc/spellcheckcontext.hxx
@@ -0,0 +1,57 @@
/* -*- 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/.
 */

#ifndef SC_SPELLCHECKCONTEXT_HXX
#define SC_SPELLCHECKCONTEXT_HXX

#include "address.hxx"
#include "editeng/misspellrange.hxx"

#include <boost/unordered_map.hpp>

namespace sc {

struct SpellCheckContext
{
    struct CellPos
    {
        struct Hash
        {
            size_t operator() (const CellPos& rPos) const;
        };

        SCCOL mnCol;
        SCROW mnRow;

        CellPos();
        CellPos(SCCOL nCol, SCROW nRow);

        void setInvalid();
        bool isValid() const;

        bool operator< (const CellPos& r) const;
        bool operator== (const CellPos& r) const;
    };

    typedef boost::unordered_map<CellPos, std::vector<editeng::MisspellRanges>, CellPos::Hash> CellMapType;

    CellPos maPos;
    CellMapType maMisspellCells;

    SpellCheckContext();

    bool isMisspelled( SCCOL nCol, SCROW nRow ) const;
    const std::vector<editeng::MisspellRanges>* getMisspellRanges( SCCOL nCol, SCROW nRow ) const;
};

}

#endif

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/app/scmod.cxx b/sc/source/ui/app/scmod.cxx
index cad7a5d..74bb24a 100644
--- a/sc/source/ui/app/scmod.cxx
+++ b/sc/source/ui/app/scmod.cxx
@@ -1941,19 +1941,17 @@ IMPL_LINK_NOARG(ScModule, IdleHandler)
        return 0;
    }

    sal_Bool bMore = false;
    ScDocShell* pDocSh = PTR_CAST( ScDocShell, SfxObjectShell::Current() );
    bool bMore = false;
    ScDocShell* pDocSh = dynamic_cast<ScDocShell*>(SfxObjectShell::Current());

    if ( pDocSh )
    {
        ScDocument* pDoc = pDocSh->GetDocument();

        sal_Bool bLinks = pDoc->IdleCheckLinks();
        sal_Bool bWidth = pDoc->IdleCalcTextWidth();
        sal_Bool bSpell = pDoc->ContinueOnlineSpelling();
        if ( bSpell )
            aSpellTimer.Start();                    // da ist noch was

        bMore = bLinks || bWidth || bSpell;         // ueberhaupt noch was?
        bMore = bLinks || bWidth;         // ueberhaupt noch was?

        //  While calculating a Basic formula, a paint event may have occurred,
        //  so check the bNeedsRepaint flags for this document's views
@@ -1961,6 +1959,17 @@ IMPL_LINK_NOARG(ScModule, IdleHandler)
            lcl_CheckNeedsRepaint( pDocSh );
    }

    ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current());
    if (pViewSh)
    {
        bool bSpell = pViewSh->ContinueOnlineSpelling();
        if (bSpell)
        {
            aSpellTimer.Start();
            bMore = true;
        }
    }

    sal_uLong nOldTime = aIdleTimer.GetTimeout();
    sal_uLong nNewTime = nOldTime;
    if ( bMore )
@@ -1996,11 +2005,10 @@ IMPL_LINK_NOARG(ScModule, SpellTimerHdl)
        return 0;                   // dann spaeter wieder...
    }

    ScDocShell* pDocSh = PTR_CAST( ScDocShell, SfxObjectShell::Current() );
    if ( pDocSh )
    ScTabViewShell* pViewSh = dynamic_cast<ScTabViewShell*>(SfxViewShell::Current());
    if (pViewSh)
    {
        ScDocument* pDoc = pDocSh->GetDocument();
        if ( pDoc->ContinueOnlineSpelling() )
        if (pViewSh->ContinueOnlineSpelling())
            aSpellTimer.Start();
    }
    return 0;
diff --git a/sc/source/ui/inc/gridwin.hxx b/sc/source/ui/inc/gridwin.hxx
index 1befc35..ba55617 100644
--- a/sc/source/ui/inc/gridwin.hxx
+++ b/sc/source/ui/inc/gridwin.hxx
@@ -32,6 +32,16 @@
#include <vector>
#include <memory>
#include <boost/scoped_ptr.hpp>
#include <boost/unordered_map.hpp>
#include <boost/ptr_container/ptr_map.hpp>

namespace editeng {
    struct MisspellRanges;
}

namespace sc {
    struct SpellCheckContext;
}

struct ScTableInfo;
class ScDPObject;
@@ -81,8 +91,6 @@ class ScGridWindow : public Window, public DropTargetHelper, public DragSourceHe
    // ScFilterListBox is always used for selection list
    friend class ScFilterListBox;

private:

    enum RfCorner
    {
        NONE,
@@ -121,9 +129,11 @@ private:
        bool isInside(SCCOL nCol, SCROW nRow) const;
        bool set(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2);
    };

    VisibleRange maVisibleRange;

private:
    boost::scoped_ptr<sc::SpellCheckContext> mpSpellCheckCxt;

    ScViewData*             pViewData;
    ScSplitPos              eWhich;
    ScHSplitPos             eHWhich;
@@ -169,7 +179,6 @@ private:

    sal_uInt16              nCurrentPointer;


    ScDDComboBoxButton      aComboButton;

    Point                   aCurMousePos;
@@ -382,6 +391,7 @@ public:
    // #114409#
    void CursorChanged();
    void DrawLayerCreated();
    bool ContinueOnlineSpelling();

    void            DeleteCopySourceOverlay();
    void            UpdateCopySourceOverlay();
diff --git a/sc/source/ui/inc/output.hxx b/sc/source/ui/inc/output.hxx
index 4565354..ec894bdb 100644
--- a/sc/source/ui/inc/output.hxx
+++ b/sc/source/ui/inc/output.hxx
@@ -27,6 +27,14 @@
#include <com/sun/star/embed/XEmbeddedObject.hpp>
#include <drawinglayer/processor2d/baseprocessor2d.hxx>

namespace sc {
    struct SpellCheckContext;
}

namespace editeng {
    struct MisspellRanges;
}

class Rectangle;
class Font;
class OutputDevice;
@@ -40,8 +48,6 @@ class ScTabViewShell;
class ScPageBreakData;
class FmFormView;
class ScFieldEditEngine;

// #i74769# SdrPaintWindow predefine
class SdrPaintWindow;

// ---------------------------------------------------------------------------
@@ -100,6 +106,7 @@ private:
        const SfxItemSet*       mpOldCondSet;
        const SfxItemSet*       mpOldPreviewFontSet;
        const RowInfo*          mpThisRowInfo;
        const std::vector<editeng::MisspellRanges>* mpMisspellRanges;

        explicit DrawEditParam(const ScPatternAttr* pPattern, const SfxItemSet* pCondSet, bool bCellIsValue);

@@ -203,6 +210,7 @@ private:

    // #i74769# use SdrPaintWindow direct, remember it during BeginDrawLayers/EndDrawLayers
    SdrPaintWindow*     mpTargetPaintWindow;
    const sc::SpellCheckContext* mpSpellCheckCxt;

                            // private methods

@@ -260,6 +268,7 @@ public:

                    ~ScOutputData();

    void SetSpellCheckContext( const sc::SpellCheckContext* pCxt );
    void    SetContentDevice( OutputDevice* pContentDev );

    void    SetRefDevice( OutputDevice* pRDev ) { mpRefDevice = pFmtDevice = pRDev; }
diff --git a/sc/source/ui/inc/tabview.hxx b/sc/source/ui/inc/tabview.hxx
index 92a42ae..69d9c54 100644
--- a/sc/source/ui/inc/tabview.hxx
+++ b/sc/source/ui/inc/tabview.hxx
@@ -520,6 +520,8 @@ public:
    void            ResetBrushDocument();

    void            SetInRefMode( bool bRefMode );

    bool ContinueOnlineSpelling();
};


diff --git a/sc/source/ui/view/gridwin.cxx b/sc/source/ui/view/gridwin.cxx
index d2fb9ac..e91d74f 100644
--- a/sc/source/ui/view/gridwin.cxx
+++ b/sc/source/ui/view/gridwin.cxx
@@ -27,6 +27,9 @@
#include <editeng/editstat.hxx>
#include <editeng/flditem.hxx>
#include <editeng/justifyitem.hxx>
#include "editeng/unolingu.hxx"
#include "editeng/langitem.hxx"
#include "editeng/misspellrange.hxx"
#include <svx/svdetc.hxx>
#include <editeng/editobj.hxx>
#include <sfx2/dispatch.hxx>
@@ -120,6 +123,9 @@
#include "checklistmenu.hrc"
#include "strload.hxx"
#include "externalrefmgr.hxx"
#include "dociter.hxx"
#include "hints.hxx"
#include "spellcheckcontext.hxx"

#include <svx/sdrpagewindow.hxx>
#include <svx/sdr/overlay/overlaymanager.hxx>
@@ -439,6 +445,7 @@ ScGridWindow::ScGridWindow( Window* pParent, ScViewData* pData, ScSplitPos eWhic
            mpOOHeader( NULL ),
            mpOOShrink( NULL ),
            mpAutoFillRect(static_cast<Rectangle*>(NULL)),
            mpSpellCheckCxt(new sc::SpellCheckContext),
            pViewData( pData ),
            eWhich( eWhichPos ),
            pNoteMarker( NULL ),
@@ -5355,6 +5362,139 @@ void ScGridWindow::DrawLayerCreated()
    ImpCreateOverlayObjects();
}

namespace {

struct SpellCheckStatus
{
    bool mbModified;

    SpellCheckStatus() : mbModified(false) {};

    DECL_LINK (EventHdl, EditStatus*);
};

IMPL_LINK(SpellCheckStatus, EventHdl, EditStatus*, pStatus)
{
    sal_uLong nStatus = pStatus->GetStatusWord();
    if (nStatus & EE_STAT_WRONGWORDCHANGED)
        mbModified = true;

    return 0;
}

}

bool ScGridWindow::ContinueOnlineSpelling()
{
    if (!mpSpellCheckCxt->maPos.isValid())
        return false;

    ScDocument* pDoc = pViewData->GetDocument();
    SCTAB nTab = pViewData->GetTabNo();
    SpellCheckStatus aStatus;

    ScHorizontalCellIterator aIter(
        pDoc, nTab, maVisibleRange.mnCol1, mpSpellCheckCxt->maPos.mnRow, maVisibleRange.mnCol2, maVisibleRange.mnRow2);

    SCCOL nCol;
    SCROW nRow;
    ScRefCellValue* pCell = aIter.GetNext(nCol, nRow);
    while (pCell && nRow < mpSpellCheckCxt->maPos.mnRow)
        pCell = aIter.GetNext(nCol, nRow);

    while (pCell && nCol < mpSpellCheckCxt->maPos.mnCol)
        pCell = aIter.GetNext(nCol, nRow);

    boost::scoped_ptr<ScTabEditEngine> pEngine;

    // Check only up to 256 cells at a time.
    size_t nTotalCellCount = 0;
    size_t nTextCellCount = 0;
    bool bChanged = false;

    while (pCell)
    {
        ++nTotalCellCount;

        CellType eType = pCell->meType;
        if (eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT)
        {
            ++nTextCellCount;

            if (!pEngine)
            {
                //  ScTabEditEngine is needed
                //  because MapMode must be set for some old documents
                pEngine.reset(new ScTabEditEngine(pDoc));
                pEngine->SetControlWord(
                    pEngine->GetControlWord() | (EE_CNTRL_ONLINESPELLING | EE_CNTRL_ALLOWBIGOBJS));
                pEngine->SetStatusEventHdl(LINK(&aStatus, SpellCheckStatus, EventHdl));
                //  Delimiters hier wie in inputhdl.cxx !!!
                pEngine->SetWordDelimiters(
                            ScEditUtil::ModifyDelimiters(pEngine->GetWordDelimiters()));

                uno::Reference<linguistic2::XSpellChecker1> xXSpellChecker1(LinguMgr::GetSpellChecker());
                pEngine->SetSpeller(xXSpellChecker1);
            }

            const ScPatternAttr* pPattern = pDoc->GetPattern(nCol, nRow, nTab);
            sal_uInt16 nCellLang =
                static_cast<const SvxLanguageItem&>(pPattern->GetItem(ATTR_FONT_LANGUAGE)).GetValue();
            if (nCellLang == LANGUAGE_SYSTEM)
                nCellLang = Application::GetSettings().GetLanguageTag().getLanguageType();   // never use SYSTEM for spelling
            pEngine->SetDefaultLanguage(nCellLang);

            if (eType == CELLTYPE_STRING)
                pEngine->SetText(*pCell->mpString);
            else
                pEngine->SetText(*pCell->mpEditText);

            aStatus.mbModified = false;
            pEngine->CompleteOnlineSpelling();
            if (aStatus.mbModified)
            {
                std::vector<editeng::MisspellRanges> aRanges;
                pEngine->GetAllMisspellRanges(aRanges);
                if (!aRanges.empty())
                {
                    sc::SpellCheckContext::CellPos aPos(nCol, nRow);
                    mpSpellCheckCxt->maMisspellCells.insert(
                        sc::SpellCheckContext::CellMapType::value_type(aPos, aRanges));
                }

                // Broadcast for re-paint.
                ScPaintHint aHint(ScRange(nCol, nRow, nTab), PAINT_GRID);
                aHint.SetPrintFlag(false);
                pDoc->GetDocumentShell()->Broadcast(aHint);
                bChanged = true;
            }
        }

        if (nTotalCellCount >= 255 || nTextCellCount >= 1)
            break;

        pCell = aIter.GetNext(nCol, nRow);
    }

    if (pCell)
        // Move to the next cell position for the next iteration.
        pCell = aIter.GetNext(nCol, nRow);

    if (pCell)
    {
        // This will become the first cell position for the next time.
        mpSpellCheckCxt->maPos.mnCol = nCol;
        mpSpellCheckCxt->maPos.mnRow = nRow;
    }
    else
    {
        // No more cells to spell check.
        mpSpellCheckCxt->maPos.setInvalid();
    }

    return bChanged;
}

// #114409#
void ScGridWindow::CursorChanged()
{
diff --git a/sc/source/ui/view/gridwin4.cxx b/sc/source/ui/view/gridwin4.cxx
index 1d2f133..7213f6a 100644
--- a/sc/source/ui/view/gridwin4.cxx
+++ b/sc/source/ui/view/gridwin4.cxx
@@ -488,6 +488,7 @@ void ScGridWindow::Draw( SCCOL nX1, SCROW nY1, SCCOL nX2, SCROW nY2, ScUpdateMod
                                &aZoomX, &aZoomY );

    aOutputData.SetMirrorWidth( nMirrorWidth );         // needed for RTL
    aOutputData.SetSpellCheckContext(mpSpellCheckCxt.get());

    std::auto_ptr< VirtualDevice > xFmtVirtDev;
    sal_Bool bLogicText = bTextWysiwyg;                     // call DrawStrings in logic MapMode?
diff --git a/sc/source/ui/view/output.cxx b/sc/source/ui/view/output.cxx
index 8f13897..1208699 100644
--- a/sc/source/ui/view/output.cxx
+++ b/sc/source/ui/view/output.cxx
@@ -207,7 +207,8 @@ ScOutputData::ScOutputData( OutputDevice* pNewDev, ScOutputType eNewType,
    bSnapPixel( false ),
    bAnyRotated( false ),
    bAnyClipped( false ),
    mpTargetPaintWindow(0) // #i74769# use SdrPaintWindow direct
    mpTargetPaintWindow(NULL), // #i74769# use SdrPaintWindow direct
    mpSpellCheckCxt(NULL)
{
    if (pZoomX)
        aZoomX = *pZoomX;
@@ -246,6 +247,11 @@ ScOutputData::~ScOutputData()
    delete pFormulaColor;
}

void ScOutputData::SetSpellCheckContext( const sc::SpellCheckContext* pCxt )
{
    mpSpellCheckCxt = pCxt;
}

void ScOutputData::SetContentDevice( OutputDevice* pContentDev )
{
    // use pContentDev instead of pDev where used
diff --git a/sc/source/ui/view/output2.cxx b/sc/source/ui/view/output2.cxx
index 77b700c..5e361c3 100644
--- a/sc/source/ui/view/output2.cxx
+++ b/sc/source/ui/view/output2.cxx
@@ -59,6 +59,7 @@
#include "docsh.hxx"
#include "markdata.hxx"
#include "stlsheet.hxx"
#include "spellcheckcontext.hxx"

#include <com/sun/star/i18n/DirectionProperty.hpp>
#include <comphelper/string.hxx>
@@ -1443,23 +1444,23 @@ void ScOutputData::DrawStrings( sal_Bool bPixelToLogic )
                nPosX -= pRowInfo[0].pCellInfo[nLoopStartX+1].nWidth * nLayoutSign;
            for (SCCOL nX=nLoopStartX; nX<=nX2; nX++)
            {
                sal_Bool bMergeEmpty = false;
                bool bMergeEmpty = false;
                CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
                sal_Bool bEmpty = nX < nX1 || pInfo->bEmptyCellText;
                bool bEmpty = nX < nX1 || pInfo->bEmptyCellText;

                SCCOL nCellX = nX;                  // position where the cell really starts
                SCROW nCellY = nY;
                sal_Bool bDoCell = false;
                sal_Bool bNeedEdit = false;
                bool bDoCell = false;
                bool bNeedEdit = false;

                //
                //  Part of a merged cell?
                //

                sal_Bool bOverlapped = ( pInfo->bHOverlapped || pInfo->bVOverlapped );
                bool bOverlapped = (pInfo->bHOverlapped || pInfo->bVOverlapped);
                if ( bOverlapped )
                {
                    bEmpty = sal_True;
                    bEmpty = true;

                    SCCOL nOverX;                   // start of the merged cells
                    SCROW nOverY;
@@ -1471,7 +1472,7 @@ void ScOutputData::DrawStrings( sal_Bool bPixelToLogic )
                        bDoCell = sal_True;
                    }
                    else
                        bMergeEmpty = sal_True;
                        bMergeEmpty = true;
                }

                //
@@ -1489,7 +1490,7 @@ void ScOutputData::DrawStrings( sal_Bool bPixelToLogic )
                         !mpDoc->HasAttrib( nTempX,nY,nTab, nX1,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) )
                    {
                        nCellX = nTempX;
                        bDoCell = sal_True;
                        bDoCell = true;
                    }
                }

@@ -1519,7 +1520,7 @@ void ScOutputData::DrawStrings( sal_Bool bPixelToLogic )
                //

                if (!bEmpty)
                    bDoCell = sal_True;
                    bDoCell = true;

                //
                //  don't output the cell that's being edited
@@ -1553,6 +1554,14 @@ void ScOutputData::DrawStrings( sal_Bool bPixelToLogic )
                    else if (aCell.meType == CELLTYPE_EDIT)
                        bNeedEdit = true;
                }

                // Check if this cell is mis-spelled.
                if (bDoCell && !bNeedEdit && aCell.meType == CELLTYPE_STRING)
                {
                    if (mpSpellCheckCxt && mpSpellCheckCxt->isMisspelled(nCellX, nCellY))
                        bNeedEdit = true;
                }

                if (bDoCell && !bNeedEdit)
                {
                    if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 )
@@ -2257,7 +2266,8 @@ ScOutputData::DrawEditParam::DrawEditParam(const ScPatternAttr* pPattern, const 
    mpOldPattern(NULL),
    mpOldCondSet(NULL),
    mpOldPreviewFontSet(NULL),
    mpThisRowInfo(NULL)
    mpThisRowInfo(NULL),
    mpMisspellRanges(NULL)
{}

bool ScOutputData::DrawEditParam::readCellContent(
@@ -2302,6 +2312,10 @@ bool ScOutputData::DrawEditParam::readCellContent(
        if ( pColor && !bSyntaxMode && !( bUseStyleColor && bForceAutoColor ) )
            lcl_SetEditColor( *mpEngine, *pColor );
    }

    if (mpMisspellRanges)
        mpEngine->SetAllMisspellRanges(*mpMisspellRanges);

    return true;
}

@@ -4576,7 +4590,7 @@ void ScOutputData::DrawEdit(sal_Bool bPixelToLogic)
                    }
                    else
                    {
                        bDoCell = sal_True;
                        bDoCell = true;
                    }

                    if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow )
@@ -4644,6 +4658,9 @@ void ScOutputData::DrawEdit(sal_Bool bPixelToLogic)
                        aParam.mpOldCondSet = pOldCondSet;
                        aParam.mpOldPreviewFontSet = pOldPreviewFontSet;
                        aParam.mpThisRowInfo = pThisRowInfo;
                        if (mpSpellCheckCxt)
                            aParam.mpMisspellRanges = mpSpellCheckCxt->getMisspellRanges(nCellX, nCellY);

                        if (aParam.meHorJust == SVX_HOR_JUSTIFY_REPEAT)
                        {
                            // ignore orientation/rotation if "repeat" is active
diff --git a/sc/source/ui/view/spellcheckcontext.cxx b/sc/source/ui/view/spellcheckcontext.cxx
new file mode 100644
index 0000000..c064d2b
--- /dev/null
+++ b/sc/source/ui/view/spellcheckcontext.cxx
@@ -0,0 +1,70 @@
/* -*- 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/.
 */

#include "spellcheckcontext.hxx"

namespace sc {

size_t SpellCheckContext::CellPos::Hash::operator() (const CellPos& rPos) const
{
    size_t nVal = rPos.mnCol;
    nVal = nVal << 4;
    nVal += rPos.mnRow;
    return nVal;
}

SpellCheckContext::CellPos::CellPos() : mnCol(0), mnRow(0) {}
SpellCheckContext::CellPos::CellPos(SCCOL nCol, SCROW nRow) : mnCol(nCol), mnRow(nRow) {}

void SpellCheckContext::CellPos::setInvalid()
{
    mnCol = -1;
    mnRow = -1;
}

bool SpellCheckContext::CellPos::isValid() const
{
    return mnCol >= 0 && mnRow >= 0;
}

bool SpellCheckContext::CellPos::operator< (const CellPos& r) const
{
    if (mnCol != r.mnCol)
        return mnCol < r.mnCol;

    return mnRow < r.mnRow;
}

bool SpellCheckContext::CellPos::operator== (const CellPos& r) const
{
    return mnCol == r.mnCol && mnRow == r.mnRow;
}

SpellCheckContext::SpellCheckContext()
{
}

bool SpellCheckContext::isMisspelled( SCCOL nCol, SCROW nRow ) const
{
    return maMisspellCells.count(CellPos(nCol, nRow)) > 0;
}

const std::vector<editeng::MisspellRanges>* SpellCheckContext::getMisspellRanges(
    SCCOL nCol, SCROW nRow ) const
{
    CellMapType::const_iterator it = maMisspellCells.find(CellPos(nCol,nRow));
    if (it == maMisspellCells.end())
        return NULL;

    return &it->second;
}

}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabview.cxx b/sc/source/ui/view/tabview.cxx
index a83fba2..3be9f36 100644
--- a/sc/source/ui/view/tabview.cxx
+++ b/sc/source/ui/view/tabview.cxx
@@ -2332,4 +2332,19 @@ void ScTabView::SetInRefMode( bool bRefMode )
        pGridWin[SC_SPLIT_TOPRIGHT]->SetInRefMode( bRefMode );
}

bool ScTabView::ContinueOnlineSpelling()
{
    bool bChanged = false;
    for (int i = 0; i < 4; ++i)
    {
        if (!pGridWin[i] || !pGridWin[i]->IsVisible())
            continue;

        if (pGridWin[i]->ContinueOnlineSpelling())
            bChanged = true;
    }

    return bChanged;
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/ui/view/tabview4.cxx b/sc/source/ui/view/tabview4.cxx
index 47fbc14..a7c4fac 100644
--- a/sc/source/ui/view/tabview4.cxx
+++ b/sc/source/ui/view/tabview4.cxx
@@ -429,18 +429,6 @@ void ScTabView::UpdateScrollBars()
    {
        if (UpdateVisibleRange())
            SC_MOD()->AnythingChanged();                // if visible area has changed

        ScSplitPos eActive = aViewData.GetActivePart();
        ScHSplitPos eHWhich = WhichH( eActive );
        ScVSplitPos eVWhich = WhichV( eActive );
        SCCOL nPosX = aViewData.GetPosX(eHWhich);
        SCROW nPosY = aViewData.GetPosY(eVWhich);
        SCCOL nEndX = nPosX + ( ( eHWhich == SC_SPLIT_LEFT ) ? nVisXL : nVisXR );
        SCROW nEndY = nPosY + ( ( eVWhich == SC_SPLIT_TOP ) ? nVisYT : nVisYB );
        if ( nEndX > MAXCOL ) nEndX = MAXCOL;
        if ( nEndY > MAXROW ) nEndY = MAXROW;
        ScRange aVisible( nPosX, nPosY, nTab, nEndX, nEndY, nTab );
        pDoc->SetVisibleSpellRange(aVisible);
    }
}