Resolves: rhbz#968892 force render full grapheme with fallback font

Change-Id: I5bb98c61d047e69d74666261b2c489d80f344502
diff --git a/vcl/generic/glyphs/gcach_layout.cxx b/vcl/generic/glyphs/gcach_layout.cxx
index 4fd4cf4..3c3c6de 100644
--- a/vcl/generic/glyphs/gcach_layout.cxx
+++ b/vcl/generic/glyphs/gcach_layout.cxx
@@ -41,6 +41,10 @@
#include <unicode/uscript.h>
#include <unicode/ubidi.h>

#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/i18n/CharacterIteratorMode.hpp>
#include <comphelper/processfactory.hxx>

// =======================================================================
// layout implementation for ServerFont
// =======================================================================
@@ -90,23 +94,42 @@ void ServerFontLayout::AdjustLayout( ImplLayoutArgs& rArgs )
    }
}

void ServerFontLayout::setNeedFallback(ImplLayoutArgs& rArgs, sal_Int32 nCharPos,
    bool bRightToLeft)
{
    if (nCharPos < 0)
        return;

    using namespace ::com::sun::star;

    if (!mxBreak.is())
    {
        uno::Reference< lang::XMultiServiceFactory > xFactory =
            comphelper::getProcessServiceFactory();
        mxBreak = uno::Reference< i18n::XBreakIterator >(xFactory->createInstance(
            "com.sun.star.i18n.BreakIterator"), uno::UNO_QUERY);
    }

    LanguageTag aLangTag(rArgs.meLanguage);
    lang::Locale aLocale(aLangTag.getLocale());

    //if position nCharPos is missing in the font, grab the entire grapheme and
    //mark all glyphs as missing so the whole thing is rendered with the same
    //font
    OUString aRun(rArgs.mpStr);
    sal_Int32 nDone;
    sal_Int32 nGraphemeStartPos =
        mxBreak->previousCharacters(aRun, nCharPos, aLocale,
            i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
    sal_Int32 nGraphemeEndPos =
        mxBreak->nextCharacters(aRun, nCharPos, aLocale,
            i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);

    rArgs.NeedFallback(nGraphemeStartPos, nGraphemeEndPos, bRightToLeft);
}

// =======================================================================

static bool lcl_CharIsJoiner(sal_Unicode cChar)
{
    return ((cChar == 0x200C) || (cChar == 0x200D));
}

static bool needPreviousCode(sal_Unicode cChar)
{
    return lcl_CharIsJoiner(cChar) || U16_IS_LEAD(cChar);
}

static bool needNextCode(sal_Unicode cChar)
{
    return lcl_CharIsJoiner(cChar) || U16_IS_TRAIL(cChar);
}

std::ostream &operator <<(std::ostream& s, ServerFont* pFont)
{
#ifndef SAL_LOG_INFO
@@ -401,9 +424,7 @@ bool HbLayoutEngine::layout(ServerFontLayout& rLayout, ImplLayoutArgs& rArgs)
            // if needed request glyph fallback by updating LayoutArgs
            if (!nGlyphIndex)
            {
                if (nCharPos >= 0)
                    rArgs.NeedFallback(nCharPos, bRightToLeft);

                rLayout.setNeedFallback(rArgs, nCharPos, bRightToLeft);
                if (SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags)
                    continue;
            }
@@ -1006,15 +1027,7 @@ bool IcuLayoutEngine::layout(ServerFontLayout& rLayout, ImplLayoutArgs& rArgs)
            // if needed request glyph fallback by updating LayoutArgs
            if( !nGlyphIndex )
            {
                if( nCharPos >= 0 )
                {
                    rArgs.NeedFallback( nCharPos, bRightToLeft );
                    if ( (nCharPos > 0) && needPreviousCode(rArgs.mpStr[nCharPos-1]) )
                        rArgs.NeedFallback( nCharPos-1, bRightToLeft );
                    else if ( (nCharPos + 1 < nEndRunPos) && needNextCode(rArgs.mpStr[nCharPos+1]) )
                        rArgs.NeedFallback( nCharPos+1, bRightToLeft );
                }

                rLayout.setNeedFallback(rArgs, nCharPos, bRightToLeft);
                if( SAL_LAYOUT_FOR_FALLBACK & rArgs.mnFlags )
                    continue;
            }
diff --git a/vcl/inc/generic/glyphcache.hxx b/vcl/inc/generic/glyphcache.hxx
index a7363f9..d6cdee1 100644
--- a/vcl/inc/generic/glyphcache.hxx
+++ b/vcl/inc/generic/glyphcache.hxx
@@ -37,6 +37,7 @@ class ImplFontOptions;
#include <boost/unordered_map.hpp>
#include <boost/unordered_set.hpp>
#include <boost/shared_ptr.hpp>
#include <com/sun/star/i18n/XBreakIterator.hpp>

namespace basegfx { class B2DPolyPolygon; }

@@ -311,6 +312,7 @@ class VCL_DLLPUBLIC ServerFontLayout : public GenericSalLayout
{
private:
    ServerFont&     mrServerFont;
    com::sun::star::uno::Reference<com::sun::star::i18n::XBreakIterator> mxBreak;

    // enforce proper copy semantic
    SAL_DLLPRIVATE  ServerFontLayout( const ServerFontLayout& );
@@ -323,6 +325,9 @@ public:
    virtual bool    LayoutText( ImplLayoutArgs& );
    virtual void    AdjustLayout( ImplLayoutArgs& );
    virtual void    DrawText( SalGraphics& ) const;
    void            setNeedFallback(ImplLayoutArgs& rArgs, sal_Int32 nIndex,
                        bool bRightToLeft);

    ServerFont&     GetServerFont() const   { return mrServerFont; }
};