Logo Search packages:      
Sourcecode: abiword version File versions

gr_Win32USPGraphics.cpp

/* AbiWord
 * Copyright (C) 2004 Tomas Frydrych <tomasfrydrych@yahoo.co.uk>
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
 * 02111-1307, USA.
 */

#include "gr_Win32USPGraphics.h"
#include "ut_debugmsg.h"
#include "xap_App.h"
#include "xap_Prefs.h"
#include "xap_Frame.h"
#include "xav_View.h"
#include "ut_Win32OS.h"

extern "C"  UT_uint16    wvLangToLIDConverter(const char * lang);
extern "C"  const char * wvLIDToLangConverter(UT_uint16);

HINSTANCE GR_Win32USPGraphics::s_hUniscribe = NULL;
UT_uint32 GR_Win32USPGraphics::s_iInstanceCount = 0;
UT_VersionInfo GR_Win32USPGraphics::s_Version;
const SCRIPT_PROPERTIES ** GR_Win32USPGraphics::s_ppScriptProperties = NULL;
int GR_Win32USPGraphics::s_iMaxScript = 0;
UT_UTF8String GR_Win32USPGraphics::s_sDescription;
UT_UTF8String GR_Win32USPGraphics::s_sUSPVersion;


tScriptItemize       GR_Win32USPGraphics::fScriptItemize       = NULL;
tScriptShape         GR_Win32USPGraphics::fScriptShape         = NULL;
tScriptFreeCache     GR_Win32USPGraphics::fScriptFreeCache     = NULL;
tScriptStringOut     GR_Win32USPGraphics::fScriptStringOut     = NULL;
tScriptStringAnalyse GR_Win32USPGraphics::fScriptStringAnalyse = NULL;
tScriptStringFree    GR_Win32USPGraphics::fScriptStringFree    = NULL;
tScriptTextOut       GR_Win32USPGraphics::fScriptTextOut       = NULL;
tScriptPlace         GR_Win32USPGraphics::fScriptPlace         = NULL;
tScriptJustify       GR_Win32USPGraphics::fScriptJustify       = NULL;
tScriptCPtoX         GR_Win32USPGraphics::fScriptCPtoX         = NULL;
tScriptXtoCP         GR_Win32USPGraphics::fScriptXtoCP         = NULL;
tScriptBreak         GR_Win32USPGraphics::fScriptBreak         = NULL;
tScriptIsComplex     GR_Win32USPGraphics::fScriptIsComplex     = NULL;
tScriptGetProperties GR_Win32USPGraphics::fScriptGetProperties = NULL;
tScriptRecordDigitSubstitution GR_Win32USPGraphics::fScriptRecordDigitSubstitution = NULL;

// some macros to ease logging of critical exceptions
// all of these macros log the file name and line where the exception occured, plus some
// additional information

// log single string
#define LOG_USP_EXCPT(msg)                                                      \
{                                                                               \
    UT_String __s;                                                              \
    UT_String_sprintf(__s, "%s (%d): %s",__FILE__, __LINE__, msg);              \
      UT_DEBUGMSG(("%s",__s.c_str()));                                            \
    if(XAP_App::getApp()->getPrefs())                                           \
    {                                                                           \
          XAP_App::getApp()->getPrefs()->log("USPGraphics", __s.c_str());         \
    }                                                                           \
}

// log string and a numerical parameter ("msg [0xpar]")
#define LOG_USP_EXCPT_X(msg, par)                                               \
{                                                                               \
    UT_String __s;                                                              \
    UT_String_sprintf(__s, "%s (%d): %s [0x%x]",__FILE__, __LINE__, msg, par);  \
      UT_DEBUGMSG(("%s",__s.c_str()));                                            \
    if(XAP_App::getApp()->getPrefs())                                           \
    {                                                                           \
          XAP_App::getApp()->getPrefs()->log("USPGraphics", __s.c_str());         \
    }                                                                           \
}

// log message consisting of two strings ("msg [str]")
#define LOG_USP_EXCPT_S(msg, str)                                               \
{                                                                               \
    UT_String __s;                                                              \
    UT_String_sprintf(__s, "%s (%d): %s [%s]",__FILE__, __LINE__, msg, str);    \
      UT_DEBUGMSG(("%s",__s.c_str()));                                            \
    if(XAP_App::getApp()->getPrefs())                                           \
    {                                                                           \
          XAP_App::getApp()->getPrefs()->log("USPGraphics", __s.c_str());         \
    }                                                                           \
}

// log string, with additional string and numerical parameters ("msg [str, 0xpar]")
#define LOG_USP_EXCPT_SX(msg, str, par)                                                  \
{                                                                                        \
    UT_String __s;                                                                       \
    UT_String_sprintf(__s, "%s (%d): %s [%s, 0x%x]",__FILE__, __LINE__, msg, str, par);  \
      UT_DEBUGMSG(("%s",__s.c_str()));                                                     \
    if(XAP_App::getApp()->getPrefs())                                                    \
    {                                                                                    \
          XAP_App::getApp()->getPrefs()->log("USPGraphics", __s.c_str());                  \
    }                                                                                    \
}

#define GR_WIN32_USP_FONT_SCALING 20
class GR_Win32USPItem: public GR_Item
{
      friend class GR_Win32USPGraphics;

  public:
      virtual ~GR_Win32USPItem(){};
      
      virtual GR_ScriptType getType() const {return (GR_ScriptType) m_si.a.eScript;}
      virtual GR_Item *     makeCopy() const {return new GR_Win32USPItem(m_si);} // make a copy of this item
      virtual GRRI_Type     getClassId() const {return GRRI_WIN32_UNISCRIBE;}

      bool isRTL() const {return m_si.a.fRTL != 0;}
      
  protected:
      GR_Win32USPItem(SCRIPT_ITEM si):m_si(si){};
      GR_Win32USPItem(GR_ScriptType t){ m_si.a.eScript = (WORD)t;};

      SCRIPT_ITEM m_si;
};

class GR_Win32USPRenderInfo : public GR_RenderInfo
{
  public:
      GR_Win32USPRenderInfo(GR_ScriptType type):
            GR_RenderInfo(type),
          m_pIndices(NULL),
          m_pVisAttr(NULL),
            m_iIndicesSize(0),
            m_pClust(NULL),
            m_iClustSize(0),
            m_iIndicesCount(0),
            m_iCharCount(0),
            m_pGoffsets(NULL),
          m_pAdvances(NULL),
            m_pJustify(NULL),
            m_iZoom(100),
            m_eJustification(SCRIPT_JUSTIFY_NONE),
            m_bRejustify(true),
            m_bShapingFailed(false),
            m_bNeedsReshaping(true),
            m_hdc(NULL)
      {
            s_iInstanceCount++;
            if(s_iInstanceCount == 1)
            {
                  allocStaticBuffers(200);
            }
            
      };
      
      virtual ~GR_Win32USPRenderInfo()
          {
                  delete [] m_pIndices;  delete [] m_pVisAttr;
                  delete [] m_pClust;    delete [] m_pGoffsets;
                  delete [] m_pAdvances; delete [] m_pJustify;

                  s_iInstanceCount--;
                  if(!s_iInstanceCount)
                  {
                        delete [] s_pAdvances; s_pAdvances = NULL;
                        delete [] s_pJustifiedAdvances; s_pJustifiedAdvances = NULL;
                        delete [] s_pJustify;  s_pJustify  = NULL;
                        delete [] s_pLogAttr;  s_pLogAttr  = NULL;
                        delete [] s_pChars;    s_pChars    = NULL;
                        delete [] s_pGoffsets; s_pGoffsets = NULL;
                        s_iAdvancesSize = 0;

                        s_pOwnerDraw = NULL;
                        s_pOwnerCP   = NULL;
                        s_pOwnerChar = NULL;
                  }
            }

      virtual GRRI_Type getType() const {return GRRI_WIN32_UNISCRIBE;}
      virtual bool      append(GR_RenderInfo &ri, bool bReverse = false);
      virtual bool      split (GR_RenderInfo *&pri, bool bReverse = false);
      virtual bool      cut(UT_uint32 offset, UT_uint32 iLen, bool bReverse = false);
      virtual bool      isJustified() const;
      
      inline bool       allocStaticBuffers(UT_uint32 iSize)
          {
                  s_iAdvancesSize = 0;
                  if(s_pAdvances) { delete [] s_pAdvances; s_pAdvances = NULL;}
                  s_pAdvances = new int [iSize];

                  if(s_pJustifiedAdvances) { delete [] s_pJustifiedAdvances; s_pJustifiedAdvances = NULL;}
                  s_pJustifiedAdvances = new int [iSize];

                  if(s_pJustify) { delete [] s_pJustify; s_pJustify = NULL; }
                  s_pJustify  = new int [iSize];

                  if(s_pLogAttr) { delete [] s_pLogAttr; s_pLogAttr = NULL; }
                  s_pLogAttr  = new SCRIPT_LOGATTR[iSize]; // log attr. correspont to characters, not glyphs, but since there are
                                                                           // always at least as many glyphs, this is OK
                  if(s_pChars) { delete [] s_pChars; s_pChars = NULL; }
                  s_pChars    = new WCHAR[iSize];

                  if(s_pGoffsets) { delete [] s_pGoffsets; s_pGoffsets = NULL; }
                  s_pGoffsets  = new GOFFSET[iSize];
                  
                  UT_return_val_if_fail(s_pAdvances && s_pJustifiedAdvances && s_pJustify &&
                                                  s_pLogAttr && s_pChars && s_pGoffsets, false);

                  s_iAdvancesSize = iSize;
                  
                  s_pOwnerDraw = NULL;
                  s_pOwnerCP = NULL;
                  s_pOwnerChar = NULL;
                  
                  return true;
          }

  public:

      WORD *           m_pIndices;
      SCRIPT_VISATTR * m_pVisAttr;
      UT_uint32        m_iIndicesSize;

      WORD *           m_pClust;
      UT_uint32        m_iClustSize;

      UT_uint32        m_iIndicesCount;
      UT_uint32        m_iCharCount;

      GOFFSET *        m_pGoffsets;  // according to the docs this should be a single structure, but it needs to be an array
      int *            m_pAdvances;
      int *            m_pJustify;
      ABC              m_ABC;
      UT_uint32        m_iZoom;

      SCRIPT_JUSTIFY   m_eJustification;

      bool             m_bRejustify;
      bool             m_bShapingFailed;
      bool             m_bNeedsReshaping;
      HDC              m_hdc;
      
      
      static int *     s_pAdvances;            // in device units, used for drawing
      static int *     s_pJustifiedAdvances;   // in logical units, used for mapping x to CP
      static UT_uint32 s_iInstanceCount;
      static UT_uint32 s_iAdvancesSize;
      static int *     s_pJustify;
      static SCRIPT_LOGATTR * s_pLogAttr;
      static WCHAR *   s_pChars;
      static GOFFSET * s_pGoffsets;
      
      // static buffer ownerhip: we use static buffers to store various positioning information; the
      // following members identify the instance that last modified these buffers
      
      static GR_RenderInfo * s_pOwnerDraw; // buffers used for drawing
      static GR_RenderInfo * s_pOwnerCP;   // buffers used for xy <--> CP translation
      static GR_RenderInfo * s_pOwnerChar; // buffers that store raw unicode text (used by
                                                             // _scriptBreak, etc.)
};

int *           GR_Win32USPRenderInfo::s_pAdvances          = NULL;
int *           GR_Win32USPRenderInfo::s_pJustifiedAdvances = NULL;
int *           GR_Win32USPRenderInfo::s_pJustify           = NULL;
UT_uint32       GR_Win32USPRenderInfo::s_iInstanceCount     = 0;
UT_uint32       GR_Win32USPRenderInfo::s_iAdvancesSize      = 0;
SCRIPT_LOGATTR *GR_Win32USPRenderInfo::s_pLogAttr           = NULL;
WCHAR *         GR_Win32USPRenderInfo::s_pChars             = NULL;
GR_RenderInfo * GR_Win32USPRenderInfo::s_pOwnerDraw         = NULL;
GR_RenderInfo * GR_Win32USPRenderInfo::s_pOwnerCP           = NULL;
GR_RenderInfo * GR_Win32USPRenderInfo::s_pOwnerChar         = NULL;
GOFFSET *       GR_Win32USPRenderInfo::s_pGoffsets          = NULL;


GR_Win32USPGraphics::GR_Win32USPGraphics(HDC hdc, HWND hwnd, XAP_App * pApp)
      :GR_Win32Graphics(hdc, hwnd, pApp),
       m_iDCFontAllocNo(0),
       m_bConstructorSucceeded(false)
{
      if(!_constructorCommonCode())
      {
            // we should only get here if exceptions were not enabled
            return;
      }

      m_bConstructorSucceeded = true;
}


GR_Win32USPGraphics::GR_Win32USPGraphics(HDC hdc, const DOCINFO * pDI, XAP_App * pApp,
                                                             HGLOBAL hDevMode)
      :GR_Win32Graphics(hdc, pDI, pApp, hDevMode),
       m_iDCFontAllocNo(0),
       m_bConstructorSucceeded(false)
{
      if(!_constructorCommonCode())
      {
            // we should only get here if exceptions were not enabled
            return;
      }

      m_bConstructorSucceeded = true;
}

GR_Win32Font * GR_Win32USPGraphics::_newFont(LOGFONT & lf, double fPoints, HDC hdc, HDC printHDC)
{
      return GR_Win32USPFont::newFont(lf, fPoints, hdc, printHDC);
}

#define loadUSPFunction(name)                           \
f##name = (t##name)GetProcAddress(s_hUniscribe, #name); \
if(!f##name)                                            \
{                                                       \
      LOG_USP_EXCPT(#name)                                \
      return false;                                       \
}

#define logScript(iId)                                                                   \
{                                                                                        \
    {                                                                                    \
          UT_String s;                                                                     \
            char _buff[100];                                                                 \
        GetLocaleInfoA(MAKELCID((WORD)s_ppScriptProperties[iId]->langid, SORT_DEFAULT),  \
                              LOCALE_SENGLANGUAGE,                                               \
                                _buff,                                                             \
                                100);                                                              \
                                                                                             \
            s += _buff;                                                                      \
                                                                                         \
            GetLocaleInfoA(MAKELCID((WORD)s_ppScriptProperties[iId]->langid, SORT_DEFAULT),  \
                              LOCALE_SENGCOUNTRY,                                                \
                                _buff,                                                             \
                                100);                                                              \
                                                                                         \
            s += " (";                                                                       \
            s += _buff;                                                                      \
            s += ")";                                                                        \
                                                                                             \
            UT_DEBUGMSG(("Uniscribe %s\n", s.c_str()));                                      \
          if(XAP_App::getApp()->getPrefs())                                                \
          {                                                                                \
               XAP_App::getApp()->getPrefs()->log("gr_Win32USPGraphics", s.c_str());         \
          }                                                                                \
    }                                                                                    \
}

bool GR_Win32USPGraphics::_constructorCommonCode()
{
      // try to load Uniscribe
      s_iInstanceCount++;
      
      if(s_iInstanceCount == 1)
      {
            s_sDescription = "Uniscribe-based graphics";
            s_Version.set(0,1,0,0);
            
            s_hUniscribe = LoadLibrary("usp10.dll");

            if(!s_hUniscribe)
            {
                  LOG_USP_EXCPT("could not load usp10.dll")
                  return false;
            }
            
#if 1 //def DEBUG
            char FileName[250];
            if(GetModuleFileName(s_hUniscribe,&FileName[0],250))
            {
                  DWORD dummy;
                  DWORD iSize = GetFileVersionInfoSize(FileName,&dummy);

                  if(iSize)
                  {
                        char * pBuff = (char*)malloc(iSize);
                        if(pBuff && GetFileVersionInfo(FileName, 0, iSize, pBuff))
                        {
                              LPVOID buff2;
                              UINT   buff2size;
                              
                              if(VerQueryValue(pBuff,"\\",
                                                       &buff2,
                                                       &buff2size))
                              {
                                    VS_FIXEDFILEINFO * pFix = (VS_FIXEDFILEINFO *) buff2;
                                    UT_uint32 iV1 = (pFix->dwFileVersionMS & 0xffff0000) >> 16;
                                    UT_uint32 iV2 = pFix->dwFileVersionMS & 0x0000ffff;
                                    UT_uint32 iV3 = (pFix->dwFileVersionLS & 0xffff0000) >> 16;
                                    UT_uint32 iV4 = pFix->dwFileVersionLS & 0x0000ffff;
                                          
                                    UT_DEBUGMSG(("GR_Win32USPGraphics: Uniscribe version %d.%d.%d.%d\n",
                                                       iV1, iV2, iV3, iV4));

                                    UT_String s;
                                    UT_String_sprintf(s, "usp10.dll: %d.%d.%d.%d", iV1, iV2, iV3, iV4);

                                    if(XAP_App::getApp()->getPrefs())
                                    {
                                          XAP_App::getApp()->getPrefs()->log("gr_Win32USPGraphics", s.c_str()); 
                                    }

                                    s_sUSPVersion = s.c_str();
                              }
                        }
                        free(pBuff);
                  }
            }
#endif

            // now we load the functions we need
            loadUSPFunction(ScriptItemize);
            loadUSPFunction(ScriptShape);
            loadUSPFunction(ScriptFreeCache);
            loadUSPFunction(ScriptStringOut);
            loadUSPFunction(ScriptStringAnalyse);
            loadUSPFunction(ScriptStringFree);
            loadUSPFunction(ScriptTextOut);
            loadUSPFunction(ScriptPlace);
            loadUSPFunction(ScriptJustify);
            loadUSPFunction(ScriptCPtoX);
            loadUSPFunction(ScriptXtoCP);
            loadUSPFunction(ScriptBreak);
            loadUSPFunction(ScriptIsComplex);
            loadUSPFunction(ScriptRecordDigitSubstitution);
            loadUSPFunction(ScriptGetProperties);
            
            HRESULT hRes = fScriptGetProperties(&s_ppScriptProperties, & s_iMaxScript);
            if(hRes)
            {
                  LOG_USP_EXCPT_X("no script properties", hRes)
                  return false;
            }
#ifdef DEBUG
            for(UT_sint32 i = 0; i < s_iMaxScript; ++i)
            {
                  logScript(i);
            }
#endif
      }
      else // we are not the first instance, USP should be loaded
      {
            if(!s_hUniscribe)
            {
                  LOG_USP_EXCPT("no USP HINST")
                  return false;
            }
      }
      
      return true;
}
#undef loadUSPFunction

GR_Win32USPGraphics::~GR_Win32USPGraphics()
{
      // have to delete all fonts before we unload usp10.dll
      // ~GR_Win32Graphics() from deleting it
      delete m_pFontGUI;
      m_pFontGUI = NULL;

      _destroyFonts();
      
      s_iInstanceCount--;
      
      if(!s_iInstanceCount)
      {
            if(s_hUniscribe)
            {
                  FreeLibrary(s_hUniscribe);
                  s_hUniscribe = NULL;
            }
      }
}

const char *    GR_Win32USPGraphics::graphicsDescriptor()
{
      return s_sDescription.utf8_str();
}

const char *    GR_Win32USPGraphics::getUSPVersion()
{
      return s_sUSPVersion.utf8_str();
}

GR_Graphics *   GR_Win32USPGraphics::graphicsAllocator(GR_AllocInfo& info)
{
      UT_return_val_if_fail(info.getType() == GRID_WIN32, NULL);
      
      GR_Win32AllocInfo &AI = (GR_Win32AllocInfo&)info;

      GR_Win32USPGraphics * pG = NULL;

      if(AI.m_pDocInfo)
      {
            // printer graphics required
            pG = new GR_Win32USPGraphics(AI.m_hdc, AI.m_pDocInfo,
                                                         AI.m_pApp,AI.m_hDevMode);
      }
      else
      {
            // screen graphics required
            pG = new GR_Win32USPGraphics(AI.m_hdc, AI.m_hwnd, AI.m_pApp);
      }

      if(pG->m_bConstructorSucceeded)
            return pG;
      else
            return NULL;
}

UT_uint32 GR_Win32USPGraphics::getFontHeight(GR_Font * fnt)
{
      UT_return_val_if_fail( fnt, 0 );
      GR_Font * pOldFont = m_pFont;
      setFont(fnt);
      
      UT_uint32 i = getFontHeight();
      if(pOldFont)
            setFont(pOldFont);
      return i;
}

UT_uint32 GR_Win32USPGraphics::getFontHeight()
{
      UT_return_val_if_fail( m_pFont, 0 );

      if(getPrintDC() != m_pFont->getYHDC())
      {
            _setupFontOnDC((GR_Win32USPFont*)m_pFont, false);
      }
      
      return (UT_uint32)((m_pFont->getHeight(m_hdc, getPrintDC())) * getResolution() / getDeviceResolution());
}

UT_uint32 GR_Win32USPGraphics::getFontAscent(GR_Font* fnt)
{
      UT_return_val_if_fail( fnt, 0 );
      GR_Font * pOldFont = m_pFont;
      setFont(fnt);
      
      UT_uint32 i = getFontAscent();
      if(pOldFont)
            setFont(pOldFont);
      return i;
}

UT_uint32 GR_Win32USPGraphics::getFontAscent()
{
      UT_return_val_if_fail( m_pFont, 0 );

      if(getPrintDC() != m_pFont->getYHDC())
      {
            _setupFontOnDC((GR_Win32USPFont*)m_pFont, false);
      }
      
      return (UT_uint32)((m_pFont->getAscent(m_hdc, getPrintDC())) * getResolution() / getDeviceResolution());
}

UT_uint32 GR_Win32USPGraphics::getFontDescent(GR_Font* fnt)
{
      UT_return_val_if_fail( fnt, 0 );
      GR_Font * pOldFont = m_pFont;
      setFont(fnt);
      
      UT_uint32 i = getFontDescent();
      if(pOldFont)
            setFont(pOldFont);
      return i;
}

UT_uint32 GR_Win32USPGraphics::getFontDescent()
{
      UT_return_val_if_fail( m_pFont, 0 );

      if(getPrintDC() != m_pFont->getYHDC())
      {
            _setupFontOnDC((GR_Win32USPFont*)m_pFont, false);
      }
      
      return (UT_uint32)((m_pFont->getDescent(m_hdc, getPrintDC())) * getResolution() / getDeviceResolution());
}

/*!
    The USP library maintains an internal font cache, which allows it to avoid accessing
    the DC for things like measuring fonts, etc. This means that often it is not necessary
    to have the font selected into the DC, and as SelectObject() is very time consuming,
    we will not be calling it from here at all, instead, we will only note which font is
    being set and call SelectObject() from inside the functions that access the DC only if
    that is necessary.
*/
void GR_Win32USPGraphics::setFont(GR_Font* pFont)
{
      m_pFont = static_cast<GR_Win32Font *>(pFont);

      UT_ASSERT_HARMLESS(pFont);    // TODO should we allow pFont == NULL?

      if(pFont)
            m_iFontAllocNo = pFont->getAllocNumber();
      else
            m_iFontAllocNo = 0;
}


void GR_Win32USPGraphics::_setupFontOnDC(GR_Win32USPFont *pFont, bool bZoomMe)
{
      UT_return_if_fail( pFont );

      UT_uint32 zoom = 0;
      UT_uint32 pixels = 0;
      HDC hdc = m_hdc;

      if(pFont->isFontGUI() || m_bPrint)
      {
            zoom = 100;
            pixels = pFont->getUnscaledHeight();
      }
      else if (bZoomMe)
      {
            // this branch gets only executed for screen draw
            // Win32 GDI uses a bigger font size for screen operations than the user request;
            // this is a real pain as it makes doing WYSIWIG near impossible. One of the
            // consequences of this is that if we do layout using printer metrics (in order to
            // achieve true WYSIWIG), the letters, particularly, the descending parts, can be
            // drawn outwith the line rectangle (and so leave pixel dirt, etc.)
            // In order to avoid that, we actually request a slightly smaller font from the
            // system if the physical pixel size drops below certain (heristically determined) value.
            zoom = getZoomPercentage();
            double dZoom = (double)zoom;
            double dSizeFactor = dZoom * (double)pFont->getUnscaledHeight()/(double)getDeviceResolution();
            // 10 pt font on 96dpi is 13px
            if(dSizeFactor <= 14.0)
            {
                  // The numerical constant is heuristic
                  // 2% decrease on a 96 dpi screen works out 1 pixel adjustment
                  dZoom /= 1.02;
            }
            
            pixels = (UT_uint32)((double)pFont->getUnscaledHeight()* dZoom/100.0) ;
      }
      else if(getPrintDC())
      {
            // we are using the printer dc for measuring, so we do not do any scaling
            zoom = 100;
            UT_uint32 iHeight = (UT_uint32)pFont->getPointSize();
            pixels = MulDiv(iHeight, m_nPrintLogPixelsY, 72);
            hdc = getPrintDC();
      }
      else
      {
            // neither GUI font, nor to be zoomed -- we will actually scale the font to a big
            // size, so that our measurements are no affected by hinting; the scaling factor
            // is fairly arbitrary and is set near the top of this file
            zoom = 100;
            pixels = pFont->getUnscaledHeight() * GR_WIN32_USP_FONT_SCALING;
      }
      
      HFONT hFont = pFont->getFontFromCache(pixels, false, zoom);
      if (!hFont)
      {
            pFont->fetchFont(pixels);
            hFont = pFont->getFontFromCache(pixels, false, zoom);
      }

      if(pFont->getAllocNumber() != m_iDCFontAllocNo ||
         (HFONT) GetCurrentObject(hdc, OBJ_FONT) != hFont)
      {
            if(NULL == SelectObject(hdc, hFont))
            {
                  DWORD e = GetLastError();
                  LPVOID lpMsgBuf;
 
                  FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                                      NULL,
                                      e,
                                      MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                                      (LPTSTR) &lpMsgBuf,
                                      0,
                                      NULL);

                  UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
                  LOGFONT lf;
                  if(GetObject(hFont, sizeof(LOGFONT), &lf))
                  {
                        // this assumes that the lfFaceName is a char string; it could be wchar in
                        // fact but it seems to work elsewhere in the win32 graphics class
                        LOG_USP_EXCPT_SX((char*)lpMsgBuf, lf.lfFaceName, lf.lfHeight)
                  }
                  else
                  {
                        LOG_USP_EXCPT("Could not select font into DC")
                  }

                  LocalFree( lpMsgBuf );
            }
            
            m_iDCFontAllocNo = pFont->getAllocNumber();
      }
}


#define GRWIN32USP_CHARBUFF_SIZE 100
#define GRWIN32USP_ITEMBUFF_SIZE 20
bool GR_Win32USPGraphics::itemize(UT_TextIterator & text, GR_Itemization & I)
{
      static WCHAR wcInChars[GRWIN32USP_CHARBUFF_SIZE];
      static SCRIPT_ITEM Items[GRWIN32USP_ITEMBUFF_SIZE];

      WCHAR *pInChars = &wcInChars[0];
      SCRIPT_ITEM * pItems = &Items[0];
      bool bDeleteChars = false;
      bool bDeleteItems = false;

      UT_return_val_if_fail(text.getStatus() == UTIter_OK, false);
      UT_uint32 iPosStart = text.getPosition();
      UT_uint32 iPosEnd   = text.getUpperLimit();
      UT_return_val_if_fail(iPosEnd < 0xffffffff && iPosEnd >= iPosStart, false);

      UT_uint32 iLen = iPosEnd - iPosStart + 1; // including iPosEnd

      if(iLen > GRWIN32USP_CHARBUFF_SIZE)
      {
            UT_DEBUGMSG(("GR_Win32USPGraphics::itemize: text buffer too small (iLen %d)\n", iLen));
            pInChars = new WCHAR[iLen];
            UT_return_val_if_fail(pInChars,false);
            bDeleteChars = true;
      }

      UT_uint32 i;
      for(i = 0; i < iLen; ++i, ++text)
      {
            UT_return_val_if_fail(text.getStatus() == UTIter_OK, false);
            pInChars[i] = (WCHAR)text.getChar();
      }
      
      int       iItemCount;
      UT_uint16 iLid = wvLangToLIDConverter(I.getLang());
      
      SCRIPT_STATE ss;
      ss.uBidiLevel = I.getEmbedingLevel();
      ss.fOverrideDirection = I.getDirOverride() == FRIBIDI_TYPE_UNSET ? 0 : 1;
      ss.fInhibitSymSwap = 0;
      ss.fCharShape = 1;
      ss.fDigitSubstitute = 1;
      ss.fInhibitLigate = 0;
      ss.fDisplayZWG = I.getShowControlChars();
      ss.fArabicNumContext = 0;
      ss.fGcpClusters = 0;
      ss.fReserved = 0;
      ss.fEngineReserved = 0;

      SCRIPT_CONTROL sc;
      sc.uDefaultLanguage = iLid; 
      sc.fContextDigits = 1; 
      sc.fInvertPreBoundDir = 0; 
      sc.fInvertPostBoundDir = 0; 
      sc.fLinkStringBefore = 0; 
      sc.fLinkStringAfter = 0; 
      sc.fNeutralOverride = 0; 
      sc.fNumericOverride = 0; 
      sc.fLegacyBidiClass = 0; 
      sc.fReserved = 0; 

            
      HRESULT hRes = fScriptItemize(pInChars, iLen, GRWIN32USP_ITEMBUFF_SIZE, &sc, &ss, pItems, &iItemCount);
      if(hRes)
      {
            UT_return_val_if_fail(hRes == E_OUTOFMEMORY, false);
            UT_uint32 iItemBuffSize = GRWIN32USP_ITEMBUFF_SIZE;
            UT_DEBUGMSG(("GR_Win32USPGraphics::itemize: item buffer too small (len %d)\n", iItemBuffSize));
            
            do
            {
                  iItemBuffSize *= 2;
                  
                  if(bDeleteItems)
                        delete [] pItems;
                  
                  pItems = new SCRIPT_ITEM[iItemBuffSize];
                  UT_return_val_if_fail(pItems, false);
                  bDeleteItems = true;

                  hRes = fScriptItemize(pInChars, iLen, iItemBuffSize, /*sc*/NULL, &ss, pItems, &iItemCount);
                  
            }while(hRes == E_OUTOFMEMORY);

            UT_return_val_if_fail(hRes == 0, false);
      }
      
      // now we process the ouptut
      for(i = 0; i < (UT_uint32)iItemCount; ++i)
      {
            GR_Win32USPItem * pI = new GR_Win32USPItem(pItems[i]);
            UT_return_val_if_fail(pI, false);

            I.addItem(pItems[i].iCharPos, pI);
      }

      I.addItem(iPosEnd - iPosStart + 1, new GR_Win32USPItem(GRScriptType_Void));


      if(bDeleteItems)
            delete [] pItems;

      if(bDeleteChars)
            delete [] pInChars;
      
      return true;
}

bool GR_Win32USPGraphics::shape(GR_ShapingInfo & si, GR_RenderInfo *& ri)
{
      UT_return_val_if_fail(si.m_pItem && si.m_pItem->getClassId() == GRRI_WIN32_UNISCRIBE && si.m_pFont, false);
      GR_Win32USPItem * pItem = (GR_Win32USPItem *)si.m_pItem;
      GR_Win32USPFont * pFont = (GR_Win32USPFont *)si.m_pFont;

      if(!ri)
      {
            ri = new GR_Win32USPRenderInfo((GR_ScriptType)pItem->m_si.a.eScript);
            UT_return_val_if_fail(ri, false);
      }
      else
      {
            UT_return_val_if_fail(ri->getType() == GRRI_WIN32_UNISCRIBE, false);
      }

      GR_Win32USPRenderInfo * RI = (GR_Win32USPRenderInfo *)ri;

            
      if(RI->m_iClustSize < (UT_uint32)si.m_iLength)
      {
            delete [] RI->m_pClust;
            RI->m_pClust = new WORD[si.m_iLength];
            UT_return_val_if_fail(RI->m_pClust, false);

            RI->m_iClustSize = si.m_iLength;
      }

      // to save time we will use a reasonably sized static buffer and
      // will only allocate one on heap if the static one is too small.
      static WCHAR wcInChars[GRWIN32USP_CHARBUFF_SIZE]; 
      WCHAR *pInChars = &wcInChars[0];
      bool bDeleteChars = false;      // using static buffer

      if(si.m_iLength > GRWIN32USP_CHARBUFF_SIZE)
      {
            UT_DEBUGMSG(("GR_Win32USPGraphics::shape: char buffer too small (len %d)\n", si.m_iLength));
            pInChars = new WCHAR[si.m_iLength];
            UT_return_val_if_fail(pInChars,false);

            bDeleteChars = true; // data on heap; cleanup later
      }

      UT_uint32 i;
      for(i = 0; i < (UT_uint32)si.m_iLength; ++i, ++si.m_Text)
      {
            UT_return_val_if_fail(si.m_Text.getStatus() == UTIter_OK, false);
            pInChars[i] = (WCHAR)si.m_Text.getChar();
      }

      // the problem with the glyph buffer is that we do no know how big
      // it needs to be, and what is worse, we will only find out by
      // trial and error; we will use a static buffer of size twice the
      // character count as the smallest buffer; this should mean that
      // most of the time we will succeed on first attempt (however, if the
      // buffer in the RI is bigger, we will use it instead)
      static WORD wGlyphs[2 * GRWIN32USP_CHARBUFF_SIZE];
      UT_uint32 iGlyphBuffSize = GRWIN32USP_CHARBUFF_SIZE *2;
      WORD *pGlyphs = &wGlyphs[0];
      
      static SCRIPT_VISATTR va[GRWIN32USP_CHARBUFF_SIZE *2];
      SCRIPT_VISATTR * pVa = &va[0];
      
      bool bCopyGlyphs = true;     // glyphs not in the RI
      bool bDeleteGlyphs = false;  // glyphs not in dynamically
                                                 // allocated memory
      
      if(GRWIN32USP_CHARBUFF_SIZE *2 < RI->m_iIndicesSize)
      {
            // use the bigger buffer in RI
            pGlyphs = RI->m_pIndices;
            pVa     = RI->m_pVisAttr;
            bCopyGlyphs = false; // glyphs directly in RI
            bDeleteGlyphs = true; // glyphs on heap
            iGlyphBuffSize = RI->m_iIndicesSize;
      }
      
      int iGlyphCount = 0;

      HDC hdc = 0;
      if(*(pFont->getScriptCache()) == NULL)
      {
            // need to make sure that the HDC has the correct font set
            // so that ScriptShape measures it correctly for the cache
            // we do not want to scale the font for this
            _setupFontOnDC(pFont, false);
            hdc = m_printHDC ? m_printHDC : m_hdc;
      }

      RI->m_bShapingFailed = false;
      RI->m_bNeedsReshaping = true;
      
      // we need to make sure that the analysis embeding level is in sync with si.m_iVisDir
      pItem->m_si.a.fRTL = si.m_iVisDir == UT_BIDI_RTL ? 1 : 0;
      HRESULT hRes = fScriptShape(hdc, pFont->getScriptCache(), pInChars, si.m_iLength,
                                                iGlyphBuffSize, & pItem->m_si.a, pGlyphs,
                                                RI->m_pClust, pVa, &iGlyphCount);

      if( hRes == E_PENDING)
      {
            UT_ASSERT_HARMLESS( hdc == 0 );

            _setupFontOnDC(pFont, false);
            hdc = m_printHDC ? m_printHDC : m_hdc;
            hRes = fScriptShape(hdc, pFont->getScriptCache(), pInChars, si.m_iLength,
                                          iGlyphBuffSize, & pItem->m_si.a, pGlyphs,
                                          RI->m_pClust, pVa, &iGlyphCount);
      }

      if(hRes == E_OUTOFMEMORY)
      {
            // glyph buffer too small ...
            do
            {
                  // try twice the buffer size
                  iGlyphBuffSize *= 2;
                  if(bDeleteGlyphs)
                  {
                        delete [] pGlyphs;
                        delete [] pVa;
                        if(RI->m_pAdvances) {delete [] RI->m_pAdvances; RI->m_pAdvances = NULL;}
                        if(RI->m_pGoffsets) {delete [] RI->m_pGoffsets; RI->m_pGoffsets = NULL;}
                        if(RI->m_pJustify)  {delete [] RI->m_pJustify;  RI->m_pJustify  = NULL;}
                  }

                  bCopyGlyphs = true; // glyphs not in RI
                  
                  pGlyphs = new WORD[iGlyphBuffSize];
                  UT_return_val_if_fail(pGlyphs, false);
                  pVa = new SCRIPT_VISATTR[iGlyphBuffSize];
                  UT_return_val_if_fail(pVa, false);
                  
                  bDeleteGlyphs = true; // glyphs in dynamically alloc. memory

                  hRes = fScriptShape(hdc, pFont->getScriptCache(), pInChars, si.m_iLength, iGlyphBuffSize,
                                             & pItem->m_si.a, pGlyphs, RI->m_pClust, pVa, &iGlyphCount);
                  
            }while(hRes == E_OUTOFMEMORY);

            UT_return_val_if_fail(hRes == 0, false);
      }
      else if(hRes)
      {
            // Some kind of other problem; this happens, for example, when the font cannot be used by
            // the shaping engine. For example, the Syriac text in World.abw fails unless it is
            // formatted with a suitable otf font (e.g. Estrangelo Edessa from Bet Marduk)
            // What we try to do as last resort is to disable shaping, and try
            // to call the function again. This will result in some or all of the glyphs in the string
            // being mapped to the missing glyph.
            
            UT_DEBUGMSG(("gr_Win32USPGraphics::shape: ScriptShape failed (hRes 0x%04x\n); disabling shaping\n"));

            // we only disable shaping temporarily, because if the font changes later, we need to try again
            RI->m_bShapingFailed = true;
            WORD eScript = pItem->m_si.a.eScript;
            pItem->m_si.a.eScript = GRScriptType_Undefined;

            hRes = fScriptShape(hdc, pFont->getScriptCache(), pInChars, si.m_iLength, iGlyphBuffSize,
                                       & pItem->m_si.a, pGlyphs, RI->m_pClust, pVa, &iGlyphCount);

            pItem->m_si.a.eScript = eScript;
            UT_return_val_if_fail(hRes == 0, false);
      }
      
      if(bDeleteGlyphs && bCopyGlyphs)
      {
            // glyphs are in dynamically allocated memory, so we just need
            // to set the pointers
            RI->m_iIndicesSize = iGlyphBuffSize;
            RI->m_pIndices = pGlyphs;
            RI->m_pVisAttr = pVa;

            if(RI->m_pAdvances) {delete [] RI->m_pAdvances; RI->m_pAdvances = NULL;}
            if(RI->m_pGoffsets) {delete [] RI->m_pGoffsets; RI->m_pGoffsets = NULL;}
            if(RI->m_pJustify)  {delete [] RI->m_pJustify;  RI->m_pJustify  = NULL;}
      }
      else if(!bDeleteGlyphs && bCopyGlyphs)
      {
            // glyphs are in a static buffer, we need to (possibly) realloc and copy

            // only realloc if necessary
            if((UT_sint32)RI->m_iIndicesSize < iGlyphCount)
            {
                  delete [] RI->m_pIndices;
                  delete [] RI->m_pVisAttr;

                  RI->m_pIndices = new WORD [iGlyphCount];
                  RI->m_pVisAttr = new SCRIPT_VISATTR [iGlyphCount];

                  // we also have to delete the other related arrays we do
                  // not need just yet to ensure that the size of all the
                  // arrays will remain in sync
                  if(RI->m_pAdvances) {delete [] RI->m_pAdvances; RI->m_pAdvances = NULL;}
                  if(RI->m_pGoffsets) {delete [] RI->m_pGoffsets; RI->m_pGoffsets = NULL;}
                  if(RI->m_pJustify)  {delete [] RI->m_pJustify;  RI->m_pJustify  = NULL;}
                  
                  UT_return_val_if_fail(RI->m_pIndices && RI->m_pVisAttr, false);
            
                  RI->m_iIndicesSize = iGlyphCount;
            }
            
            memcpy(RI->m_pIndices, pGlyphs, iGlyphCount * sizeof(WORD));
            memcpy(RI->m_pVisAttr, pVa, iGlyphCount * sizeof(SCRIPT_VISATTR));
      }
      else if (bDeleteGlyphs && !bCopyGlyphs)
      {
            // glyphs are already in the RI, just need to set the correct
            // size for the buffers
            RI->m_iIndicesSize = iGlyphBuffSize;

            if(RI->m_pAdvances) {delete [] RI->m_pAdvances; RI->m_pAdvances = NULL;}
            if(RI->m_pGoffsets) {delete [] RI->m_pGoffsets; RI->m_pGoffsets = NULL;}
            if(RI->m_pJustify)  {delete [] RI->m_pJustify;  RI->m_pJustify  = NULL;}
      }
      else
      {
            // !bDeleteGlyphs && !bCopyGlyphs
            UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
      }

      // need to transfer data that we will need later from si to RI
      RI->m_iLength = si.m_iLength;
      RI->m_iIndicesCount = iGlyphCount;
      RI->m_pItem = si.m_pItem;
      RI->m_pFont = si.m_pFont;
      RI->m_iCharCount = si.m_iLength;
      RI->m_bNeedsReshaping = false;
      
      // once we implement the GR_Win32USPRenderInfo::append(), etc., we
      // should enable this; until then we need to treat everything as
      // complex and have it refreshed on merges, etc.
#if 0
      // work out shaping result
      DWORD dFlags = SIC_COMPLEX;

      if(si.m_iVisDir == UT_BIDI_RTL)
            dFlags |= SIC_NEUTRAL;

      SCRIPT_DIGITSUBSTITUTE sds;
      if(S_OK == fScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &sds))
      {
            if(sds.DigitSubstitute != SCRIPT_DIGITSUBSTITUTE_NONE)
                  dFlags |= SIC_ASCIIDIGIT;
      }

      HRESULT hShape = fScriptIsComplex(pInChars, si.m_iLength, dFlags);
      if(hShape == S_OK)
            RI->m_eShapingResult = GRSR_ContextSensitiveAndLigatures;
      else
            RI->m_eShapingResult = GRSR_None;
#else
      RI->m_eShapingResult = GRSR_ContextSensitiveAndLigatures;
#endif
      
      if(bDeleteChars)
      {
            delete [] pInChars;
      }

      if(RI->s_pOwnerChar == RI)
      {
            // this might not be strictly necessary, but it is safer to do so
            // no, this is necessary
            RI->s_pOwnerChar = NULL;
      }
      
      return true;
}

UT_sint32 GR_Win32USPGraphics::getTextWidth(GR_RenderInfo & ri)
{
      UT_return_val_if_fail(ri.getType() == GRRI_WIN32_UNISCRIBE, 0);
      GR_Win32USPRenderInfo & RI = (GR_Win32USPRenderInfo &)ri;
      GR_Win32USPFont * pFont = (GR_Win32USPFont*)RI.m_pFont;

      // NB -- do not have to check for zoom as the internal metrics is always for 100%
      if(pFont->getPrintDC() != getPrintDC() || RI.m_hdc != getPrintDC())
      {
            measureRenderedCharWidths(ri);
      }
      

      
#if 0
      // as neat as this is, we cannot use it, because due to the hinting errors, this is a
      // different number than our sum of character widths
      if(!RI.m_pJustify && ri.m_iOffset == 0 && ri.m_iLength == (UT_sint32)RI.m_iCharCount)
            return (RI.m_ABC.abcA + RI.m_ABC.abcB + RI.m_ABC.abcC);
#endif
      
      UT_return_val_if_fail(ri.m_iOffset + ri.m_iLength <= (UT_sint32)RI.m_iCharCount, 0);
      
      UT_sint32 iWidth = 0;
      GR_Win32USPItem & I = (GR_Win32USPItem &)*ri.m_pItem;
      bool bReverse = I.m_si.a.fRTL != 0;

      for(UT_sint32 i = ri.m_iOffset; i < ri.m_iLength + ri.m_iOffset; ++i)
      {
            if(!bReverse)
            {
                  UT_uint32 iMax = RI.m_iIndicesCount;
                  
                  if(i < (UT_sint32)RI.m_iCharCount - 1)
                        iMax = RI.m_pClust[i+1];

                  for(UT_uint32 j = RI.m_pClust[i]; j < iMax; ++j)
                  {
                        iWidth += RI.m_pAdvances[j];

                        if(RI.m_pJustify)
                              iWidth += RI.m_pJustify[j];
                  }
            }
            else
            {
                  UT_sint32 iMin = -1;
                  
                  // The offset is a logical offset, and clusters are in logical order.  Indices, however,
                  // are in visual order, and the clusters reference glyph indices, so that clust[i] >
                  // clust[i+1]

                  if(i < (UT_sint32)RI.m_iCharCount - 1)
                        iMin = RI.m_pClust[i+1];

                  for(UT_sint32 j = (UT_sint32)RI.m_pClust[i]; j > iMin; --j)
                  {
                        iWidth += RI.m_pAdvances[j];

                        if(RI.m_pJustify)
                              iWidth += RI.m_pJustify[j];
                  }
            }
      }

      return iWidth;
}

void GR_Win32USPGraphics::prepareToRenderChars(GR_RenderInfo & ri)
{
      // since we internally store widths in layout units, we need to
      // scale them down to device
      UT_return_if_fail(ri.getType() == GRRI_WIN32_UNISCRIBE);
      GR_Win32USPRenderInfo & RI = (GR_Win32USPRenderInfo &)ri;
      UT_uint32 iZoom = getZoomPercentage();
      GR_Win32USPFont * pFont = (GR_Win32USPFont*)RI.m_pFont;

#ifdef DEBUG
      UT_uint32 iPoints = (UT_uint32)pFont->getPointSize();
#endif
      
      if(iZoom == RI.m_iZoom && RI.s_pOwnerDraw == & ri && pFont->getPrintDC() != getPrintDC())
      {
            // the buffer is up-to-date
            return;
      }

      // NB -- do not have to check for zoom as the internal metrics is always for 100%
      if(pFont->getPrintDC() != getPrintDC())
      {
            // this happens when we change printer
            // we need to recalculate the widths ...
            measureRenderedCharWidths(ri);
      }
      
      if(RI.s_iAdvancesSize < RI.m_iIndicesCount)
      {
            UT_return_if_fail(RI.allocStaticBuffers(RI.m_iIndicesCount));
      }

      UT_sint32 iWidth = 0;
      UT_sint32 iNextAdvance = 0;
      UT_sint32 iAdvance = 0;

      UT_sint32 iWidthJ = 0;
      UT_sint32 iNextAdvanceJ = 0;
      UT_sint32 iAdvanceJ = 0;
      
      for(UT_uint32 i = 0; i < RI.m_iIndicesCount; ++i)
      {
            iWidth += RI.m_pAdvances[i];
            iNextAdvance = (UT_sint32)((double)_tduX(iWidth) * m_fXYRatio);
            RI.s_pAdvances[i] = iNextAdvance - iAdvance;
            iAdvance = iNextAdvance;

            // I use tdu here, not _tduX, _tduY, because the goffsets are adjustments relative
            // to the x,y offsets of the character
            RI.s_pGoffsets[i].du = (long)((double)tdu(RI.m_pGoffsets[i].du) * m_fXYRatio);
            RI.s_pGoffsets[i].dv = tdu(RI.m_pGoffsets[i].dv);
            
            
            if(RI.m_pJustify)
            {
                  iWidthJ += RI.m_pAdvances[i] + RI.m_pJustify[i];
                  iNextAdvanceJ = (UT_sint32)((double)_tduX(iWidthJ) * m_fXYRatio);
                  RI.s_pJustify[i] = iNextAdvanceJ - iAdvanceJ;
                  iAdvanceJ = iNextAdvanceJ;
            }
      }

      // there are two situations in which we need to recalculate the static positioning
      // buffers, (a) the buffer is not ours, or, (b) we have last calculated its contents
      // at different zomm level. Furthermore, if we detect a zoom change, we need to
      // invalidate the screen ascent value for the current font
      if(RI.m_iZoom != iZoom)
            pFont->setScreenAscent(0);
      
      RI.m_iZoom = iZoom;
      RI.s_pOwnerDraw = &ri;
}

/*!
    The offset passed to us as part of ri is a visual offset
*/
void GR_Win32USPGraphics::renderChars(GR_RenderInfo & ri)
{
      UT_return_if_fail(ri.getType() == GRRI_WIN32_UNISCRIBE);
      GR_Win32USPRenderInfo & RI = (GR_Win32USPRenderInfo &)ri;
      GR_Win32USPFont * pFont = (GR_Win32USPFont *)RI.m_pFont;
      GR_Win32USPItem * pItem = (GR_Win32USPItem *)RI.m_pItem;
      UT_return_if_fail(pItem && pFont);

      UT_sint32 xoff = (UT_sint32)((double)_tduX(RI.m_xoff) * m_fXYRatio);

      // we will deal with yoff later
      if(RI.m_iLength == 0)
            return;
      
      UT_return_if_fail(RI.m_iOffset + RI.m_iLength <= (UT_sint32)RI.m_iCharCount);

      UT_uint32 iGlyphCount = RI.m_iIndicesCount;
      UT_uint32 iGlyphOffset = 0;

      GR_Win32USPItem & I = (GR_Win32USPItem &)*ri.m_pItem;
      bool bReverse = I.m_si.a.fRTL != 0;

      // need logical offset to access cluster information
      UT_uint32 iOffset = bReverse ? RI.m_iCharCount - RI.m_iOffset - 1 : RI.m_iOffset;

      if(RI.m_iOffset != 0)
      {
            // we need to work out glyph offset
            iGlyphOffset = RI.m_pClust[iOffset];
      }

      if(RI.m_iOffset + RI.m_iLength == (UT_sint32)RI.m_iCharCount)
      {
            // drawing from the offset to the end
            iGlyphCount -= iGlyphOffset;
      }
      else
      {
            // work out glyph length
            iOffset = bReverse ? RI.m_iCharCount - (RI.m_iOffset + RI.m_iLength) - 1 : RI.m_iOffset + RI.m_iLength;
            UT_uint32 iOffsetEnd = RI.m_pClust[iOffset];
            iGlyphCount = iOffsetEnd - iGlyphOffset;
      }

      if(RI.m_bInvalidateFontCache)
      {
            fScriptFreeCache(pFont->getScriptCache());
            *(pFont->getScriptCache()) = NULL;
            RI.m_bInvalidateFontCache = false;
      }

      // need to make sure that the HDC has the correct font set
      // we scale this font
      _setupFontOnDC(pFont, true);

      // Now deal with y offset: RI.m_yoff is the top of the run, based on the ascent of the
      // font; if we are drawing on screen and using printer metrics to do the layout, the
      // ascent of the screen font can be smaller/greater and so we need to adjust the yoff
      // accordingly
      UT_sint32 yoff;

      if(m_bPrint)
      {
            yoff = _tduY(RI.m_yoff);
      }
      else
      {
            UT_sint32 iAscentScreen = pFont->getScreenAscent();

            if(!iAscentScreen)
            {
                  TEXTMETRIC tm = { 0 };
                  GetTextMetrics(m_hdc, &tm);
                  iAscentScreen = (UT_sint32)((double)tm.tmAscent*(double)getResolution()*100.0/
                                                            ((double)getDeviceResolution()*(double)getZoomPercentage()));
            
                  pFont->setScreenAscent(iAscentScreen);
            }

            UT_sint32 iAscentPrint = pFont->getTextMetric().tmAscent * getResolution() / getDeviceResolution();
            yoff = _tduY(RI.m_yoff + iAscentPrint - iAscentScreen);
      }
      
      int * pJustify = RI.m_pJustify && RI.m_bRejustify ? RI.s_pJustify + iGlyphOffset : NULL;
      
      // not sure how expensive SetBkMode is, but GetBkMode() should not
      // be ...
      if(GetBkMode(m_hdc) != TRANSPARENT)
      {
            SetBkMode(m_hdc, TRANSPARENT); // this is necessary
      }
      
      UINT dFlags = 0;

      // need to disapble shaping if call to ScriptShape failed ...
      WORD eScript = pItem->m_si.a.eScript;
      if(RI.m_bShapingFailed)
            pItem->m_si.a.eScript = GRScriptType_Undefined;

      HRESULT hRes = fScriptTextOut(m_hdc, pFont->getScriptCache(), xoff, yoff,
                                                  dFlags, /*option flags*/
                                                  NULL, /*not sure about this*/
                                                  & pItem->m_si.a,
                                                  NULL, 0, /*reserved*/
                                                  RI.m_pIndices  + iGlyphOffset,
                                                  iGlyphCount,
                                                  RI.s_pAdvances + iGlyphOffset,
                                                  pJustify,
                                                  RI.s_pGoffsets + iGlyphOffset);

      pItem->m_si.a.eScript = eScript;
      //RI.m_bRejustify = false; -- the docs are misleading; rejustification is always needed

      if(hRes)
      {
            UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
            LOG_USP_EXCPT_X("fScriptTextOut failed", hRes)
      }
}

void GR_Win32USPGraphics::setPrintDC(HDC dc)
{
      // only do this for screen graphics
      if(!m_bPrint && dc != m_printHDC)
      {
            // since this is a printer DC we have to delete it once not needed
            // the win32 graphics does not delete the printer dc, which is a bug in the pure
            // win32 graphics class, but exactly what we need here.
            if(m_printHDC)
                  DeleteDC(m_printHDC);
            
            m_printHDC = dc;

            if(getPrintDC())
            {
                  m_nPrintLogPixelsY = GetDeviceCaps(getPrintDC(), LOGPIXELSY);
                  int nLogPixelsX = GetDeviceCaps(getPrintDC(), LOGPIXELSX);
                  if(m_nPrintLogPixelsY)
                  {
                        m_fXYRatioPrint = (double)nLogPixelsX / (double) m_nPrintLogPixelsY;
                  }
                  else
                  {
                        UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
                        m_fXYRatioPrint = 1;
                  }
            }
            if(m_printHDC)
            {
                  // now make our views to rebuild themselves ...
                  XAP_App * pApp = XAP_App::getApp();
                  UT_return_if_fail( pApp );

                  UT_uint32 iFrameCount = pApp->getFrameCount();
                  for(UT_uint32 i = 0; i < iFrameCount; i++)
                  {
                        XAP_Frame * pFrame = pApp->getFrame(i);
                        if(!pFrame)
                              continue;

                        AV_View * pView = pFrame->getCurrentView();
                        if(pView)
                        {
                              GR_Graphics * pG = pView->getGraphics();

                              if(pG == this)
                                    pView->rebuildLayout();
                        }
                  }
            }
      }
}



void GR_Win32USPGraphics::measureRenderedCharWidths(GR_RenderInfo & ri)
{
      UT_return_if_fail(ri.getType() == GRRI_WIN32_UNISCRIBE && ri.m_pFont);
      GR_Win32USPRenderInfo & RI = (GR_Win32USPRenderInfo &)ri;
      GR_Win32USPFont * pFont = (GR_Win32USPFont *)RI.m_pFont;
      GR_Win32USPItem * pItem = (GR_Win32USPItem *)RI.m_pItem;
      UT_return_if_fail(pFont && pItem );

      if(!RI.m_pAdvances)
            RI.m_pAdvances = new int[RI.m_iIndicesSize];

      if(!RI.m_pGoffsets)
            RI.m_pGoffsets = new GOFFSET[RI.m_iIndicesSize];

      UT_uint32 iZoom = getZoomPercentage();
      
#ifdef DEBUG
      UT_uint32 iPoints = (UT_uint32)pFont->getPointSize();
#endif

      bool bFontSetUpOnDC = false;
      
      // the script cache is always containing data for 100% zoom, we scale widths manually later
      // but we need to refresh it if the printer changed
      //if(iZoom != RI.m_iZoom)
      if(pFont->getPrintDC() != getPrintDC())
      {
            // the zoom factor has changed; make sure we invalidate the cache
            if(*(pFont->getScriptCache()) != NULL)
            {
                  fScriptFreeCache(pFont->getScriptCache());
                  *(pFont->getScriptCache()) = NULL;
            }

            if(getPrintDC())
            {
                  // we also need to remeasure the font metrics as well
                  // and scale it down for the screen
                  _setupFontOnDC(pFont, false);
                  bFontSetUpOnDC = true;
                  
                  TEXTMETRIC tm = { 0 };
                  GetTextMetrics(getPrintDC(), &tm);

#if 0 //def DEBUG
                  HDC printHDC = UT_GetDefaultPrinterDC();
                  TEXTMETRIC tm2 = { 0 };
                  GetTextMetrics(printHDC, &tm2);
                  DeleteDC(printHDC);
#endif
                  pFont->setHeight(MulDiv(tm.tmHeight, getDeviceResolution(), m_nPrintLogPixelsY));
                  pFont->setAscent(MulDiv(tm.tmAscent, getDeviceResolution(), m_nPrintLogPixelsY));
                  pFont->setDescent(MulDiv(tm.tmDescent, getDeviceResolution(), m_nPrintLogPixelsY));
            }
      }

      // store the print DC used to measure the font in the font ...
      pFont->setPrintDC(getPrintDC());
      
      HDC hdc = 0;
      if(*(pFont->getScriptCache()) == NULL)
      {
            // need to make sure that the HDC has the correct font set
            // we do not scale the font by zoom
            if(!bFontSetUpOnDC)
            {
                  _setupFontOnDC(pFont, false);
                  bFontSetUpOnDC = true;
            }
            
            hdc = m_printHDC ? m_printHDC : m_hdc;

            // we remember the hdc for which we measured so we can remeasure when hdc changes
            RI.m_hdc = hdc;
      }
      else
      {
            RI.m_hdc = pFont->getPrintDC();
      }
      

      
      // need to disapble shaping if call to ScriptShape failed ...
      WORD eScript = pItem->m_si.a.eScript;
      if(RI.m_bShapingFailed)
            pItem->m_si.a.eScript = GRScriptType_Undefined;
      
      HRESULT hRes = fScriptPlace(hdc, pFont->getScriptCache(), RI.m_pIndices,
                                                RI.m_iIndicesCount, RI.m_pVisAttr,
                                                & pItem->m_si.a, RI.m_pAdvances, RI.m_pGoffsets, & RI.m_ABC);

      if( hRes == E_PENDING)
      {
            UT_ASSERT_HARMLESS( hdc == 0 );
            _setupFontOnDC(pFont, false);
            bFontSetUpOnDC = true;
            
            hdc = m_printHDC ? m_printHDC : m_hdc;

            // we remember the hdc for which we measured so we can remeasure when hdc changes
            RI.m_hdc = hdc;
            
            hRes = fScriptPlace(hdc, pFont->getScriptCache(), RI.m_pIndices,
                                          RI.m_iIndicesCount, RI.m_pVisAttr,
                                          & pItem->m_si.a, RI.m_pAdvances, RI.m_pGoffsets, & RI.m_ABC);
      }
      

      pItem->m_si.a.eScript = eScript;

      // remember the zoom at which we calculated this ...
      // RI.m_iZoom = iZoom;

      if(RI.s_pOwnerDraw == & ri)
      {
            // we currently own the static buffers; invalidate
            RI.s_pOwnerDraw = NULL;
      }

      if(RI.s_pOwnerCP == & ri)
      {
            // we currently own the static buffers; invalidate
            RI.s_pOwnerCP = NULL;
      }

      // now convert the whole lot to layout units
      double dWidth = 0;
      double dDeviceWidth = 0;
      double dPrevDeviceWidth = 0;
      
      if(getPrintDC())
      {
            double fXYRatio = m_fXYRatio * m_fXYRatioPrint;

            for(UT_uint32 i = 0; i < RI.m_iIndicesCount; ++i)
            {
                  // RI.m_pAdvances[i] = tlu(RI.m_pAdvances[i]);
                  dWidth += (double)RI.m_pAdvances[i];
                  dDeviceWidth = dWidth*(double)getResolution()
                                                         /((double)m_nPrintLogPixelsY*fXYRatio);
                  RI.m_pAdvances[i] = (UT_sint32)(dDeviceWidth - dPrevDeviceWidth + 0.5);
                  dPrevDeviceWidth = dDeviceWidth;

                  RI.m_pGoffsets[i].du = (UT_sint32)((double)RI.m_pGoffsets[i].du*(double)getResolution()
                                                                  /((double)m_nPrintLogPixelsY*fXYRatio) + 0.5);
                  RI.m_pGoffsets[i].dv = (UT_sint32)((double)RI.m_pGoffsets[i].dv*(double)getResolution()
                                                                  /((double)m_nPrintLogPixelsY) + 0.5);
            }

            //RI.m_ABC.abcA = tlu(RI.m_ABC.abcA);
            //RI.m_ABC.abcB = tlu(RI.m_ABC.abcB);
            //RI.m_ABC.abcC = tlu(RI.m_ABC.abcC);
            RI.m_ABC.abcA = (UT_sint32)((double) RI.m_ABC.abcA * (double)getResolution()
                                                      /((double)m_nPrintLogPixelsY*fXYRatio) + 0.5);
            RI.m_ABC.abcB = (UT_sint32)((double) RI.m_ABC.abcB * (double)getResolution()
                                                      /((double)m_nPrintLogPixelsY*fXYRatio) + 0.5);
            RI.m_ABC.abcC = (UT_sint32)((double) RI.m_ABC.abcC * (double)getResolution()
                                                      /((double)m_nPrintLogPixelsY*fXYRatio) + 0.5);
      }
      else if (m_bPrint)
      {
            for(UT_uint32 i = 0; i < RI.m_iIndicesCount; ++i)
            {
                  // RI.m_pAdvances[i] = tlu(RI.m_pAdvances[i]);
                  dWidth += (double)RI.m_pAdvances[i];
                  dDeviceWidth = dWidth*(double)getResolution()/
                                                         ((double)getDeviceResolution()*m_fXYRatio);
                  
                  RI.m_pAdvances[i] = (UT_sint32)(dDeviceWidth - dPrevDeviceWidth + 0.5);
                  dPrevDeviceWidth = dDeviceWidth;

                  RI.m_pGoffsets[i].du = (UT_sint32)((double)RI.m_pGoffsets[i].du*(double)getResolution()/
                                                                  ((double)getDeviceResolution()*m_fXYRatio) + 0.5);
                  RI.m_pGoffsets[i].dv = (UT_sint32)((double)RI.m_pGoffsets[i].dv*(double)getResolution()/
                                                                  ((double)getDeviceResolution()) + 0.5);
            }

            //RI.m_ABC.abcA = tlu(RI.m_ABC.abcA);
            //RI.m_ABC.abcB = tlu(RI.m_ABC.abcB);
            //RI.m_ABC.abcC = tlu(RI.m_ABC.abcC);
            RI.m_ABC.abcA = (UT_sint32)((double) RI.m_ABC.abcA * (double)getResolution() /
                                                      ((double)getDeviceResolution()*m_fXYRatio) + 0.5);
            RI.m_ABC.abcB = (UT_sint32)((double) RI.m_ABC.abcB * (double)getResolution() /
                                                      ((double)getDeviceResolution()*m_fXYRatio) + 0.5);
            RI.m_ABC.abcC = (UT_sint32)((double) RI.m_ABC.abcC * (double)getResolution() /
                                                      ((double)getDeviceResolution()*m_fXYRatio) + 0.5);
      }
      else
      {
            for(UT_uint32 i = 0; i < RI.m_iIndicesCount; ++i)
            {
                  // RI.m_pAdvances[i] = tlu(RI.m_pAdvances[i]);
                  dWidth += (double)RI.m_pAdvances[i];
                  dDeviceWidth = dWidth*(double)getResolution()/
                                                         ((double)getDeviceResolution()*(double)GR_WIN32_USP_FONT_SCALING*m_fXYRatio);
                  
                  RI.m_pAdvances[i] = (UT_sint32)(dDeviceWidth - dPrevDeviceWidth + 0.5);
                  dPrevDeviceWidth = dDeviceWidth;

                  RI.m_pGoffsets[i].du = (UT_sint32)((double)RI.m_pGoffsets[i].du*(double)getResolution()/
                                                                  ((double)getDeviceResolution()*(double)GR_WIN32_USP_FONT_SCALING*m_fXYRatio) + 0.5);
                  RI.m_pGoffsets[i].dv = (UT_sint32)((double)RI.m_pGoffsets[i].dv*(double)getResolution()/
                                                                  ((double)getDeviceResolution()*(double)GR_WIN32_USP_FONT_SCALING) + 0.5);
            }

            //RI.m_ABC.abcA = tlu(RI.m_ABC.abcA);
            //RI.m_ABC.abcB = tlu(RI.m_ABC.abcB);
            //RI.m_ABC.abcC = tlu(RI.m_ABC.abcC);
            RI.m_ABC.abcA = (UT_sint32)((double) RI.m_ABC.abcA * (double)getResolution() /
                                                      ((double)getDeviceResolution() * (double)GR_WIN32_USP_FONT_SCALING*m_fXYRatio) + 0.5);
            RI.m_ABC.abcB = (UT_sint32)((double) RI.m_ABC.abcB * (double)getResolution() /
                                                      ((double)getDeviceResolution() * (double)GR_WIN32_USP_FONT_SCALING*m_fXYRatio) + 0.5);
            RI.m_ABC.abcC = (UT_sint32)((double) RI.m_ABC.abcC * (double)getResolution() /
                                                      ((double)getDeviceResolution() * (double)GR_WIN32_USP_FONT_SCALING*m_fXYRatio) + 0.5);
      }
      
      RI.m_bRejustify = true;
      

      if(hRes)
      {
            UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
            LOG_USP_EXCPT_X("fScriptPlace failed", hRes)
      }
}

void GR_Win32USPGraphics::appendRenderedCharsToBuff(GR_RenderInfo & ri, UT_GrowBuf & buf) const
{
      UT_return_if_fail( UT_NOT_IMPLEMENTED );
}
/*!
    returns true on success
 */
bool GR_Win32USPGraphics::_scriptBreak(GR_Win32USPRenderInfo &ri)
{
      UT_return_val_if_fail(ri.getType() == GRRI_WIN32_UNISCRIBE && ri.m_pText && ri.m_pItem, false);
      
      if(ri.s_pOwnerChar != &ri)
      {
            UT_return_val_if_fail(ri.m_pText->getStatus() == UTIter_OK, false);
            UT_uint32 iPosStart = ri.m_pText->getPosition();
            UT_uint32 iPosEnd   = ri.m_pText->getUpperLimit();
            UT_return_val_if_fail(iPosEnd < 0xffffffff && iPosEnd >= iPosStart, false);

            UT_uint32 iLen = UT_MIN(iPosEnd - iPosStart + 1, (UT_uint32)ri.m_iLength); // including iPosEnd

            ri.s_pOwnerChar = &ri;
            
            if(ri.s_iAdvancesSize < iLen)
            {
                  UT_return_val_if_fail( ri.allocStaticBuffers(iLen),false);
            }
            
            for(UT_uint32 i = 0; i < iLen; ++i, ++(*(ri.m_pText)))
            {
                  ri.s_pChars[i] = (WCHAR)ri.m_pText->getChar();
            }

            GR_Win32USPItem &I = (GR_Win32USPItem &)*ri.m_pItem;
            HRESULT hRes = fScriptBreak(ri.s_pChars, iLen, &I.m_si.a, ri.s_pLogAttr);

            UT_return_val_if_fail(!hRes,false);
      }

      return true;
}

/*!
    this function should return true if break can occur AFTER the character at indicated
    position; Uniscribe functions indicate if break can occur BEFORE the character
*/
bool GR_Win32USPGraphics::canBreak(GR_RenderInfo & ri, UT_sint32 &iNext, bool bAfter)
{
      // for now we will call ScriptBreak from here; should this be too
      // much of a bottle neck, we will store the values (but we are
      // already storing loads of data per char)
      UT_return_val_if_fail(ri.getType() == GRRI_WIN32_UNISCRIBE && ri.m_iOffset < ri.m_iLength, false);
      GR_Win32USPRenderInfo & RI = (GR_Win32USPRenderInfo &)ri;
      iNext = -1;

      if(!_scriptBreak(RI))
            return false;

      if(ri.m_iLength > (UT_sint32)RI.s_iAdvancesSize)
      {
            UT_return_val_if_fail( RI.allocStaticBuffers(ri.m_iLength),false );
      }
      
      
      if(_needsSpecialBreaking(RI))
      {
            UT_uint32 iDelta  = 0;
#if 1
            if(bAfter)
            {
                  // the caller wants to know if break can occur on the (logically) right edge of the given
                  // character
                  if(ri.m_iOffset + 1 == ri.m_iLength)
                  {
                        // we are quering the last char of a run, for which we do not have the info
                        // we will return false, which should force the next run to be examined ...
                        return false;
                  }

                  // we will examine the next character, since USP tells us about breaking on the left edge
                  iDelta = 1;
            }
#endif
            if(RI.s_pLogAttr[ri.m_iOffset + iDelta].fSoftBreak)
                  return true;

            // find the next break
            for(UT_sint32 i = ri.m_iOffset + iDelta + 1; i < RI.m_iLength; ++i)
            {
                  if(RI.s_pLogAttr[i].fSoftBreak)
                  {
                        iNext = i - iDelta;
                        break;
                  }
            }
      }
      else
      {
            // we look for white-space break points, so we do not adjust the offset for bAfter
            if(RI.s_pLogAttr[ri.m_iOffset].fWhiteSpace)
                  return true;

            // find the next break
            for(UT_sint32 i = ri.m_iOffset; i < RI.m_iLength; ++i)
            {
                  if(RI.s_pLogAttr[i].fWhiteSpace)
                  {
                        iNext = i;
                        break;
                  }
            }
      }
      
      return false;
}

bool GR_Win32USPGraphics::_needsSpecialBreaking(GR_Win32USPRenderInfo &ri)
{
      UT_return_val_if_fail(s_ppScriptProperties && ri.m_pItem, false);
      if(ri.m_bShapingFailed)
            return false;
      
      return (s_ppScriptProperties[ri.m_pItem->getType()]->fNeedsWordBreaking != 0);
}

UT_uint32 GR_Win32USPGraphics::adjustCaretPosition(GR_RenderInfo & ri, bool bForward)
{
      // for now we will call ScriptBreak from here; since most of the time caret changes happen on
      // the same line, this should not be a performance problem
      UT_return_val_if_fail(ri.getType() == GRRI_WIN32_UNISCRIBE, ri.m_iOffset);
      GR_Win32USPRenderInfo & RI = (GR_Win32USPRenderInfo &)ri;

      if(!_needsSpecialCaretPositioning(RI))
            return ri.m_iOffset;

      if(!_scriptBreak(RI))
            return ri.m_iOffset;

      UT_sint32 iPos = (UT_sint32)ri.m_iOffset;
      
      if(bForward)
      {
            while(iPos < ri.m_iLength && !RI.s_pLogAttr[iPos].fCharStop)
                  iPos++;

            // iPos == m_iLength, we reached the end of the run -- we will assumed the position
            // immediately after the run implicitely valid, so we do no adjustments.
      }
      else
      {
            while(iPos >= 0 && !RI.s_pLogAttr[iPos].fCharStop)
                  iPos--;

            if(iPos < 0)
            {
                  // it would seem that the runs starts in illegal character; we return 0
                  iPos = 0;
            }
            
      }

      return (UT_uint32)iPos;
}

void GR_Win32USPGraphics::adjustDeletePosition(GR_RenderInfo & ri)
{
      // for now we will call ScriptBreak from here; since most of the time caret changes happen on
      // the same line, this should not be a performance problem
      UT_return_if_fail(ri.getType() == GRRI_WIN32_UNISCRIBE);
      GR_Win32USPRenderInfo & RI = (GR_Win32USPRenderInfo &)ri;

      if(ri.m_iLength >= (UT_sint32)RI.m_iCharCount)
      {
            // we are deleting the last character of the run, or past it; we will assume that clusters
            // do not cross run boundaries and allow the deletion happen
            return;
      }

      if(!_needsSpecialCaretPositioning(RI))
            return;

      // _scriptBreak expects the length of the segment to process to be set in ri.m_iLength which
      // currently holds the length of the deletion (we always process the whole run, as this
      // simplifies things)
      UT_uint32 iCharCount = ri.m_iLength;
      ri.m_iLength = RI.m_iCharCount;
      
      if(!_scriptBreak(RI))
            return;

      // deletion can start anywhere, but can only end on cluster boundary if the base character is
      // included in the deletion
      
      // get the offset of the character that follows the delete segment
      UT_sint32 iNextOffset = (UT_sint32)ri.m_iOffset + iCharCount;

      if(RI.s_pLogAttr[iNextOffset].fCharStop)
      {
            // the next char is a valid caret position, so we are OK
            // restore the original length
            ri.m_iLength = iCharCount;
            return;
      }

      // If we got this far, we were asked to end the deletion before a character that is not a valid
      // caret position. We need to determine if the segment we are asked to delete contains thi
      // character's base character; if it does, we have to expand the seletion to delete the entire
      // cluster.

      UT_sint32 iOffset = iNextOffset - 1;
      while(iOffset > 0 && iOffset > ri.m_iOffset && !RI.s_pLogAttr[iOffset].fCharStop)
            iOffset--;

      if(RI.s_pLogAttr[iOffset].fCharStop)
      {
            // our delete segment includes the base character, so we have to delete the entire cluster
            iNextOffset = iOffset + 1;
            
            while(iNextOffset < (UT_sint32)RI.m_iCharCount
                    && !RI.s_pLogAttr[iNextOffset].fCharStop)
                  iNextOffset++;

            
            ri.m_iLength = iNextOffset - ri.m_iOffset;
            return;
      }
      
      // two posibilities: we are deleting only a cluster appendage or the run does not contain
      // base character. The latter should probably not happen, but in both cases we will let the
      // delete proceed as is

      // restore the original length
      ri.m_iLength = iCharCount;
}
bool GR_Win32USPGraphics::needsSpecialCaretPositioning(GR_RenderInfo & ri)
{
      UT_return_val_if_fail(ri.getType() == GRRI_WIN32_UNISCRIBE, false);
      GR_Win32USPRenderInfo & RI = (GR_Win32USPRenderInfo &)ri;
      
      return _needsSpecialCaretPositioning(RI);
}
      

bool GR_Win32USPGraphics::_needsSpecialCaretPositioning(GR_Win32USPRenderInfo &ri)
{
      UT_return_val_if_fail(s_ppScriptProperties && ri.m_pItem, false);
      if(ri.m_bShapingFailed)
            return false;

      return (s_ppScriptProperties[ri.m_pItem->getType()]->fNeedsCaretInfo != 0);
}



UT_sint32 GR_Win32USPGraphics::resetJustification(GR_RenderInfo & ri, bool bPermanent)
{
      UT_return_val_if_fail(ri.getType() == GRRI_WIN32_UNISCRIBE, 0);
      GR_Win32USPRenderInfo & RI = (GR_Win32USPRenderInfo &)ri;

      if(!RI.m_pJustify)
            return 0;
      
      //UT_sint32 iWidth1 = 0;
      UT_sint32 iWidth2 = 0;
      for(UT_uint32 i = 0; i < RI.m_iIndicesCount; ++i)
      {
            //iWidth1 += RI.m_pAdvances[i];
            iWidth2 += RI.m_pJustify[i];
      }

      if(bPermanent)
      {
            delete [] RI.m_pJustify;
            RI.m_pJustify = NULL;
      }
      else
      {
            memset(RI.m_pJustify, 0, RI.m_iIndicesSize * sizeof(int));
      }
      
      if(RI.s_pOwnerDraw == & RI)
            RI.s_pOwnerDraw = NULL;

      if(RI.s_pOwnerCP == & RI)
            RI.s_pOwnerCP = NULL;
      
      return -iWidth2;
}

UT_sint32 GR_Win32USPGraphics::countJustificationPoints(const GR_RenderInfo & ri) const
{
      UT_return_val_if_fail(ri.getType() == GRRI_WIN32_UNISCRIBE && ri.m_pItem, 0);
      GR_Win32USPRenderInfo & RI = (GR_Win32USPRenderInfo &)ri;
      UT_return_val_if_fail(RI.m_pVisAttr,0);
      
      UT_sint32 iCountSpace     = 0;
      UT_sint32 iCountSpaceAR   = 0;
      UT_sint32 iCountKashida   = 0;
      UT_sint32 iCountInterChar = 0;
      bool bBlank = true; // will change to false if we find anything
                                    // that we do not have a counter for

      // we have to work from the end to the beginning, which means decreasing index in LTR and
      // increasing it in RTL
      UT_sint32 i, iInc, iLimit, iStart;

      GR_Win32USPItem * pItem = (GR_Win32USPItem *) ri.m_pItem;

      if(pItem->m_si.a.fRTL)
      {
            iStart = 0;
            iInc = 1;
            iLimit = RI.m_iIndicesCount;
      }
      else
      {
            iStart = RI.m_iIndicesCount - 1;
            iInc = -1;
            iLimit = -1;
      }
      
      bool bFoundNonBlank = !ri.m_bLastOnLine; // treat items that are not last on line as non-blank
      for(i = iStart; i != iLimit; i += iInc)
      {
            if(!bFoundNonBlank)
            {
                  if(RI.m_pVisAttr[i].uJustification == SCRIPT_JUSTIFY_BLANK)
                  {
                        // this is a trailing blank character, ignore it ...
                        continue;
                  }
                  else
                  {
                        bFoundNonBlank = true;
                  }
            }
            
            switch(RI.m_pVisAttr[i].uJustification)
            {
                  case SCRIPT_JUSTIFY_ARABIC_BLANK:
                        iCountSpaceAR++;
                        break;
                        
                  case SCRIPT_JUSTIFY_CHARACTER:
                        iCountInterChar++;
                        break;
                        
                  case SCRIPT_JUSTIFY_BLANK:
                        iCountSpace++;
                        break;
                        
                  case SCRIPT_JUSTIFY_ARABIC_NORMAL:
                  case SCRIPT_JUSTIFY_ARABIC_KASHIDA:
                  case SCRIPT_JUSTIFY_ARABIC_ALEF:
                  case SCRIPT_JUSTIFY_ARABIC_HA:
                  case SCRIPT_JUSTIFY_ARABIC_RA:
                  case SCRIPT_JUSTIFY_ARABIC_BA:
                  case SCRIPT_JUSTIFY_ARABIC_BARA:
                  case SCRIPT_JUSTIFY_ARABIC_SEEN:
                        iCountKashida++;
                        break;
                        
                  case SCRIPT_JUSTIFY_NONE:
                  case SCRIPT_JUSTIFY_RESERVED1:
                  case SCRIPT_JUSTIFY_RESERVED2:
                  case SCRIPT_JUSTIFY_RESERVED3:
                  default:
                        bBlank = false;
            }
      }

      // now we need to make sense of the stats
      if(iCountKashida)
      {
            RI.m_eJustification = (SCRIPT_JUSTIFY)(
                                    SCRIPT_JUSTIFY_ARABIC_NORMAL
                              & SCRIPT_JUSTIFY_ARABIC_KASHIDA
                                  & SCRIPT_JUSTIFY_ARABIC_ALEF
                                  & SCRIPT_JUSTIFY_ARABIC_HA
                                  & SCRIPT_JUSTIFY_ARABIC_RA
                                  & SCRIPT_JUSTIFY_ARABIC_BA
                              & SCRIPT_JUSTIFY_ARABIC_BARA
                                  & SCRIPT_JUSTIFY_ARABIC_SEEN
                                  & SCRIPT_JUSTIFY_BLANK );
            
            return iCountSpace + iCountKashida;
      }
      
      if(iCountSpace)
      {
            RI.m_eJustification = SCRIPT_JUSTIFY_BLANK;
            if(bBlank && !iCountInterChar)
                  return -iCountSpace;
            else
                  return iCountSpace;
      }

      if(iCountSpaceAR)
      {
            RI.m_eJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
            if(bBlank && !iCountInterChar)
                  return -iCountSpaceAR;
            else
                  return iCountSpaceAR;
      }
      
      // only use intercharacter justification if the script requires it
      if(iCountInterChar && s_ppScriptProperties[ri.m_pItem->getType()]->fNeedsCharacterJustify)
      {
            RI.m_eJustification = SCRIPT_JUSTIFY_CHARACTER;
            return iCountInterChar;
      }

      RI.m_eJustification = SCRIPT_JUSTIFY_NONE;
      return 0;
}

void GR_Win32USPGraphics::justify(GR_RenderInfo & ri)
{
      UT_return_if_fail(ri.getType() == GRRI_WIN32_UNISCRIBE && ri.m_pItem);
      GR_Win32USPRenderInfo & RI = (GR_Win32USPRenderInfo &)ri;

      if(!RI.m_iJustificationPoints || !RI.m_iJustificationAmount)
            return;
      
      if(!RI.m_pJustify)
            RI.m_pJustify = new int[RI.m_iIndicesSize];

      // mark the static width caches dirty
      if(RI.s_pOwnerDraw == & RI)
            RI.s_pOwnerDraw = NULL;

      if(RI.s_pOwnerCP == & RI)
            RI.s_pOwnerCP = NULL;
      
      UT_return_if_fail(RI.m_pJustify);
      memset(RI.m_pJustify, 0, RI.m_iIndicesSize * sizeof(int));
      
      UT_uint32 iExtraSpace = RI.m_iJustificationAmount;
      UT_uint32 iPoints     = RI.m_iJustificationPoints;
      GR_Win32USPItem * pItem = (GR_Win32USPItem *) ri.m_pItem;
      
      for(UT_uint32 i = 0; i < RI.m_iIndicesCount; ++i)
      {
            UT_uint32 k = pItem->m_si.a.fRTL ? RI.m_iIndicesCount - i - 1: i;
            if(RI.m_pVisAttr[k].uJustification & RI.m_eJustification)
            {
                  UT_uint32 iSpace = iExtraSpace/iPoints;
                  iExtraSpace -= iSpace;
                  iPoints--;

                  RI.m_pJustify[k] = iSpace;

                  if(!iPoints)
                        break;
            }
      }

      UT_ASSERT_HARMLESS( !iExtraSpace );
}

UT_uint32 GR_Win32USPGraphics::XYToPosition(const GR_RenderInfo & ri, UT_sint32 x, UT_sint32 y) const
{
      UT_return_val_if_fail(ri.getType() == GRRI_WIN32_UNISCRIBE, 0);
      GR_Win32USPRenderInfo & RI = (GR_Win32USPRenderInfo &) ri;
      GR_Win32USPItem * pItem = (GR_Win32USPItem *)RI.m_pItem;
      UT_return_val_if_fail(pItem, 0);

      // x = tdu(x); -- no conversion here, since we keep m_pAdvances in
      // layout units
      
      int iPos;
      int iTrail;
      int * pAdvances = RI.m_pJustify ? RI.s_pJustifiedAdvances : RI.m_pAdvances;
      
      if(RI.m_pJustify && RI.s_pOwnerCP != &RI)
      {
            if(RI.s_iAdvancesSize < RI.m_iIndicesCount)
            {
                  UT_return_val_if_fail( RI.allocStaticBuffers (RI.m_iIndicesCount), 0);
            }
            
            
            for(UT_uint32 i  = 0; i < RI.m_iIndicesCount; ++i)
            {
                  RI.s_pJustifiedAdvances[i] = RI.m_pAdvances[i] + RI.m_pJustify[i];
            }

            RI.s_pOwnerCP = &RI;
      }
      
      HRESULT hRes = fScriptXtoCP(x, RI.m_iLength, RI.m_iIndicesCount, RI.m_pClust,
                                                RI.m_pVisAttr, pAdvances,
                                                & pItem->m_si.a, &iPos, &iTrail);

      if(hRes)
      {
            UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
            LOG_USP_EXCPT_X("fScriptXtoCP failed", hRes)
      }

      return iPos + iTrail;
}

void GR_Win32USPGraphics::positionToXY(const GR_RenderInfo & ri,
                                                              UT_sint32& x, UT_sint32& y,
                                                              UT_sint32& x2, UT_sint32& y2,
                                                              UT_sint32& height, bool& bDirection) const
{
      UT_return_if_fail(ri.getType() == GRRI_WIN32_UNISCRIBE);
      GR_Win32USPRenderInfo & RI = (GR_Win32USPRenderInfo &) ri;
      GR_Win32USPItem * pItem = (GR_Win32USPItem *)RI.m_pItem;
      //UT_uint32 iZoom = getZoomPercentage();
      
      if(!pItem)
            return;

      bool bTrailing = true;

      int * pAdvances = RI.m_pJustify ? RI.s_pJustifiedAdvances : RI.m_pAdvances;
      
      if(RI.m_pJustify && RI.s_pOwnerCP != &RI)
      {
            if( RI.s_iAdvancesSize < RI.m_iIndicesCount)
            {
                  UT_return_if_fail( RI.allocStaticBuffers(RI.m_iIndicesCount));
            }
            
            
            for(UT_uint32 i  = 0; i < RI.m_iIndicesCount; ++i)
            {
                  RI.s_pJustifiedAdvances[i] = RI.m_pAdvances[i] + RI.m_pJustify[i];
            }

            RI.s_pOwnerCP = &RI;
      }
      
      HRESULT hRes = fScriptCPtoX(RI.m_iOffset,
                                             bTrailing, /* fTrailing*/
                                             RI.m_iLength, RI.m_iIndicesCount, RI.m_pClust, RI.m_pVisAttr,
                                             pAdvances, & pItem->m_si.a, &x);

      

      if(hRes)
      {
            UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
            LOG_USP_EXCPT_X("fScriptCPtoX failed", hRes)
      }

      x = x;
      x2 = x;
}

void GR_Win32USPGraphics::drawChars(const UT_UCSChar* pChars,
                                                      int iCharOffset, int iLength,
                                                      UT_sint32 xoff, UT_sint32 yoff,
                                                      int * /*pCharWidth*/)
{
      if(!pChars || ! iLength)
            return;
      
      if(GetBkMode(m_hdc) != TRANSPARENT)
      {
            SetBkMode(m_hdc, TRANSPARENT); // this is necessary
      }

      static WCHAR buff[100];
      WCHAR * pwChars = buff;
    bool bDelete = false;
      
      if(iLength > 100)
      {
            pwChars = new WCHAR[iLength];
            bDelete = true;
      }

      UT_sint32 i = 0;
      for(i = 0; i < iLength; ++i)
      {
            pwChars[i] = pChars[i+iCharOffset];
      }
      
      SCRIPT_STRING_ANALYSIS SSA;
      UT_uint32 flags = SSA_GLYPHS;

      // need to make sure that the HDC has the correct font set
      // so that ScriptShape measures it correctly for the cache
      GR_Win32USPFont * pFont = static_cast<GR_Win32USPFont *>(m_pFont);
      _setupFontOnDC(pFont, true);
      
      HRESULT hRes = fScriptStringAnalyse(m_hdc, pwChars, iLength, iLength*3/2 + 1,
                                    -1, flags, 0, NULL, NULL, NULL, NULL, NULL, &SSA);

      if(hRes)
      {
            UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
            LOG_USP_EXCPT_X("fScriptStringAnalyse failed", hRes)
      }
      
      hRes = fScriptStringOut(SSA, (UT_sint32)((double)_tduX(xoff) * m_fXYRatio), _tduY(yoff), 0, NULL, 0, 0, FALSE);

      if(hRes)
      {
            UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
            LOG_USP_EXCPT_X("fScriptStringOut failed", hRes)
      }

      if(SSA)
            fScriptStringFree(&SSA);

      if(bDelete)
            delete [] pwChars;
}


//////////////////////////////////////////////////////////////////////////////
//
// GR_WinUSPRenderInfo Implementation
//

bool GR_Win32USPRenderInfo::append(GR_RenderInfo &ri, bool bReverse)
{
      //UT_return_val_if_fail( UT_NOT_IMPLEMENTED, false );
      m_bNeedsReshaping = true;
      
      return false;
}

bool GR_Win32USPRenderInfo::split (GR_RenderInfo *&pri, bool bReverse)
{
      UT_return_val_if_fail(m_pGraphics && m_pFont, false);

      UT_ASSERT_HARMLESS(!pri);
      if(!pri)
      {
            pri = new GR_Win32USPRenderInfo(m_eScriptType);
            UT_return_val_if_fail(pri,false);
      }

      pri->m_pItem = m_pItem->makeCopy();
      UT_return_val_if_fail(pri->m_pItem, false);

      m_bNeedsReshaping = true;
      return false;
      
      // trying to split the data is just too precarious ...
#if 0

      if(m_bNeedsReshaping)
      {
            // we have not been shaped, so that is all we can do for the caller
            return false;
      }
      
      GR_Win32USPRenderInfo & RI = (GR_Win32USPRenderInfo &) *pri;
      RI.m_bShapingFailed = m_bShapingFailed;
      
      UT_return_val_if_fail( (UT_sint32)m_iClustSize > m_iOffset, false );

      GR_Win32USPItem &I = (GR_Win32USPItem &)*m_pItem;
      
      UT_uint32 iGlyphOffset = m_pClust[m_iOffset];

      if(I.isRTL())
      {
            // need to include the glyph at the offset as well
            iGlyphOffset++;
      }
      
      UT_uint32 iGlyphLen1 = iGlyphOffset;
      UT_uint32 iGlyphLen2 = m_iIndicesCount - iGlyphLen1;

      if(I.isRTL())
      {
            UT_uint32 t = iGlyphLen1;
            iGlyphLen1 =  iGlyphLen2;
            iGlyphLen2 = t;
      }
      
      UT_uint32 iCharLen1 = m_iOffset;
      UT_uint32 iCharLen2 = m_iCharCount - iCharLen1;

      // this is an attempt to simply split the data, but I am not sure
      // what to do about the ABC and GOFFSET, hence we recalculate the
      // placements
      if(RI.m_iIndicesSize < iGlyphLen2)
      {
            delete [] RI.m_pIndices;  RI.m_pIndices  = new WORD [iGlyphLen2];
            delete [] RI.m_pAdvances; RI.m_pAdvances = new int  [iGlyphLen2];
            delete [] RI.m_pVisAttr;  RI.m_pVisAttr  = new SCRIPT_VISATTR [iGlyphLen2];
            delete [] RI.m_pGoffsets; RI.m_pGoffsets = new GOFFSET[iGlyphLen2];

            UT_return_val_if_fail(RI.m_pIndices && RI.m_pAdvances && RI.m_pVisAttr, false);
            
            if(m_pJustify)
            {
                  delete [] RI.m_pJustify; RI.m_pJustify = new int [iGlyphLen2];
                  memset(RI.m_pJustify, 0, iGlyphLen2 * sizeof(int));;
                  UT_return_val_if_fail(RI.m_pJustify, false);
            }
            
            RI.m_iIndicesSize = iGlyphLen2;
      }

      if(RI.m_iClustSize < iCharLen2)
      {
            delete [] RI.m_pClust; RI.m_pClust = new WORD [iCharLen2];
            UT_return_val_if_fail(RI.m_pClust, false);
            RI.m_iClustSize = iCharLen2;
      }

      if(I.isRTL())
      {
            UT_uint32 i;
            // RI is the first segment of the visual buffers
            memcpy(RI.m_pIndices, m_pIndices, sizeof(WORD)*iGlyphLen2);
            memcpy(RI.m_pVisAttr,  m_pVisAttr, sizeof(SCRIPT_VISATTR)*iGlyphLen2);

            // now we need to copy the cluster info (relative to the original start
            // of the string)
            for(i = 0; i < iCharLen2; ++i)
            {
                  RI.m_pClust[i] = m_pClust[i+m_iOffset];
            }
            
            memmove(m_pIndices, m_pIndices + iGlyphOffset, sizeof(WORD)*iGlyphLen1);
            memmove(m_pVisAttr, m_pVisAttr + iGlyphOffset, sizeof(SCRIPT_VISATTR)*iGlyphLen1);

            // now we need to copy the cluster info (relative to the original start
            // of the string)
            for(i = 0; i < iCharLen1; ++i)
            {
                  m_pClust[i] = m_pClust[i] - iCharLen2;
            }
      }
      else
      {
            memcpy(RI.m_pIndices,  m_pIndices  + iGlyphOffset, sizeof(WORD)*iGlyphLen2);
            memcpy(RI.m_pVisAttr,  m_pVisAttr  + iGlyphOffset, sizeof(SCRIPT_VISATTR)*iGlyphLen2);

            // now we need to copy the cluster info (relative to the original start
            // of the string)
            for(UT_uint32 i = 0; i < iCharLen2; ++i)
            {
                  RI.m_pClust[i] = m_pClust[i+m_iOffset] - m_iOffset;
            }
      }
      
      m_iIndicesCount = iGlyphLen1; RI.m_iIndicesCount = iGlyphLen2;
      m_iCharCount    = iCharLen1;  RI.m_iCharCount    = iCharLen2;
      RI.m_pGraphics = m_pGraphics;
      RI.m_pFont = m_pFont;

      RI.m_eShapingResult = m_eShapingResult;
      RI.m_eState = m_eState;
      RI.m_hdc = m_hdc;

      GR_Graphics * pG = const_cast<GR_Graphics*>(m_pGraphics);

      pri->m_bLastOnLine = m_bLastOnLine;
      m_bLastOnLine = false;
      
      pG->measureRenderedCharWidths(*this);
      pG->measureRenderedCharWidths(*pri);

      if(m_pJustify && m_iJustificationPoints)
      {
            UT_uint32 iJustAmount = m_iJustificationAmount;
            UT_uint32 iJustPoints = m_iJustificationPoints;
            
            m_iJustificationPoints = pG->countJustificationPoints(*this);
            pri->m_iJustificationPoints = pG->countJustificationPoints(*pri);

            pri->m_iJustificationAmount = iJustAmount * pri->m_iJustificationPoints / iJustPoints;
            m_iJustificationAmount = iJustAmount - pri->m_iJustificationAmount;
      }
      

      if(s_pOwnerChar == &RI)
      {
            s_pOwnerChar = NULL;
      }
      
      return true;
#endif
}

bool GR_Win32USPRenderInfo::cut(UT_uint32 offset, UT_uint32 iLen, bool bReverse)
{
      //UT_return_val_if_fail( UT_NOT_IMPLEMENTED, false );
      m_bNeedsReshaping = true;
      
      return false;
}

bool GR_Win32USPRenderInfo::isJustified() const
{
      return (m_pJustify != NULL);
}

GR_Win32USPFont *  GR_Win32USPFont::newFont(LOGFONT &lf, double fPoints, HDC hdc, HDC printHDC)
{
      GR_Win32USPFont * f = new GR_Win32USPFont(lf, fPoints, hdc, printHDC);

      if(!f || !f->getFontHandle())
      {
            delete f;
            f = NULL;
      }

      return f;
}

GR_Win32USPFont::GR_Win32USPFont(LOGFONT & lf, double fPoints, HDC hdc, HDC printHDC)
      : GR_Win32Font(lf, fPoints, hdc, printHDC),
        m_sc(NULL),
        m_printHDC(NULL),
        m_iScreenAscent(0)
{
};

void GR_Win32USPFont::_clearAnyCachedInfo()
{
      if(m_sc != NULL)
      {
            GR_Win32USPGraphics::fScriptFreeCache(&m_sc);
            m_sc = NULL;
      }
}

GR_Win32USPFont::~GR_Win32USPFont()
{
      GR_Win32USPGraphics::fScriptFreeCache(&m_sc);
}


/*********************************/
/* General plugin stuff */
/*********************************/
#ifndef GR_WIN32USP_BUILTIN

#include "xap_Module.h"
#include "xap_App.h"

#ifdef ABI_PLUGIN_BUILTIN
#define abi_plugin_register abipgn_grwin32usp_register
#define abi_plugin_unregister abipgn_grwin32usp_unregister
#define abi_plugin_supports_version abipgn_grwin32usp_supports_version
#endif

static      UT_uint32 s_iPrevDefaultScreen = 0;
static      UT_uint32 s_iPrevDefaultPrinter = 0;

ABI_PLUGIN_DECLARE("gr_Win32USPGraphics")

ABI_FAR_CALL
int abi_plugin_register (XAP_ModuleInfo * mi)
{
      mi->name    = PLUGIN_NAME;
      mi->desc    = "";
      mi->version = "0.1.0.0";
      mi->author  = "Tomas Frydrych <tomasfrydrych@yahoo.co.uk";
      mi->usage   = "";

      UT_VersionInfo v1(0,1,0,0);
      
      XAP_App * pApp = XAP_App::getApp();
      UT_return_val_if_fail(pApp, 0);

      GR_GraphicsFactory * pGF = pApp->getGraphicsFactory();
      UT_return_val_if_fail(pGF, 0);
      
      if(!pGF->registerClass(GR_Win32USPGraphics::graphicsAllocator,
                                       GR_Win32USPGraphics::graphicsDescriptor,
                                       GR_Win32USPGraphics::s_getClassId()))
      {
            // OK, there is a class already registered with our id
            // (probably a built-in version of this class) -- get its
            // version info and replace it if ours is higher
            GR_Win32AllocInfo ai;
            GR_Graphics * pG = pApp->newGraphics(GR_Win32USPGraphics::s_getClassId(), ai);
            UT_return_val_if_fail(pG, 0);

            const UT_VersionInfo & v2 = pG->getVersion();
            if(v1 > v2)
            {
                  // first we need to see if this class is registered as the
                  // default graphics class; if so we need to changed that
                  // to the basic win32 class before we can unregister it
                  // we also need to remember the previous values so we can
                  // restore them when we are unloaded
                  s_iPrevDefaultScreen  = pGF->getDefaultClass(true);
                  s_iPrevDefaultPrinter = pGF->getDefaultClass(false);
                  
                  if(s_iPrevDefaultScreen == GR_Win32USPGraphics::s_getClassId())
                  {
                        s_iPrevDefaultScreen = GRID_WIN32;
                        pGF->registerAsDefault(GRID_WIN32, true);
                  }
                  
                  if(s_iPrevDefaultPrinter == GR_Win32USPGraphics::s_getClassId())
                  {
                        s_iPrevDefaultPrinter = GRID_WIN32;
                        pGF->registerAsDefault(GRID_WIN32, false);
                  }

                  if(!pGF->unregisterClass(GR_Win32USPGraphics::s_getClassId()
                  || !pGF->registerClass(GR_Win32USPGraphics::graphicsAllocator,
                                                   GR_Win32USPGraphics::graphicsDescriptor,
                                                   GR_Win32USPGraphics::s_getClassId())))
                  {
                        UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
                        delete pG;
                        return 0;
                  }
            }
            else
            {
                  delete pG;
                  return 0;
            }

            delete pG;
      }

      pGF->registerAsDefault(GR_Win32USPGraphics::s_getClassId(), true);
      pGF->registerAsDefault(GR_Win32USPGraphics::s_getClassId(), false);
      
      return 1;
}

ABI_FAR_CALL
int abi_plugin_unregister (XAP_ModuleInfo * mi)
{
      mi->name = 0;
      mi->desc = 0;
      mi->version = 0;
      mi->author = 0;
      mi->usage = 0;

      XAP_App * pApp = XAP_App::getApp();
      UT_return_val_if_fail(pApp, 0);

      GR_GraphicsFactory * pGF = pApp->getGraphicsFactory();
      UT_return_val_if_fail(pGF, 0);
      
      if(pGF->getDefaultClass(true) == GR_Win32USPGraphics::s_getClassId())
      {
            if(pGF->isRegistered(s_iPrevDefaultScreen))
            {
                  pGF->registerAsDefault(s_iPrevDefaultScreen, true);
            }
            else
            {
                  pGF->registerAsDefault(GRID_WIN32, true);
            }
      }
      
      if(pGF->getDefaultClass(false) == GR_Win32USPGraphics::s_getClassId())
      {
            if(pGF->isRegistered(s_iPrevDefaultPrinter))
            {
                  pGF->registerAsDefault(s_iPrevDefaultPrinter, false);
            }
            else
            {
                  pGF->registerAsDefault(GRID_WIN32, false);
            }
      }
      
      return 1;
}

ABI_FAR_CALL
int abi_plugin_supports_version (UT_uint32 major, UT_uint32 minor, 
                         UT_uint32 release)
{

      return 1;
}
#endif

Generated by  Doxygen 1.6.0   Back to index