void GR_UnixCairoGraphics::scroll(UT_sint32 dx, UT_sint32 dy)
{
	UT_sint32 oldDY = tdu(getPrevYOffset());
	UT_sint32 oldDX = tdu(getPrevXOffset());
	UT_sint32 newY = getPrevYOffset() + dy;
	UT_sint32 newX = getPrevXOffset() + dx;
	UT_sint32 ddx = -(tdu(newX) - oldDX);
	UT_sint32 ddy = -(tdu(newY) - oldDY);
	setPrevYOffset(newY);
	setPrevXOffset(newX);
	if(ddx == 0 && ddy == 0)
	{
		return;
	}

	disableAllCarets();

	UT_sint32 iddy = labs(ddy);
	bool bEnableSmooth = XAP_App::getApp()->isSmoothScrollingEnabled();
	bEnableSmooth = bEnableSmooth && (iddy < 30) && (ddx == 0);
	if(bEnableSmooth)
	{
		if(ddy < 0)
		{
			UT_sint32 i = 0;
			for(i = 0; i< iddy; i++)
			{
				gdk_window_scroll(m_pWin,0,-1);
			}
		}
		else
		{
			UT_sint32 i = 0;
			for(i = 0; i< iddy; i++)
			{
				gdk_window_scroll(m_pWin,0,1);
			}
		}
	}
	else
	{
		gdk_window_scroll(m_pWin,ddx,ddy);
	}
	enableAllCarets();
}
/*!
 * This method converts rectangle widths and heights to device units while 
 * taking account rounding down errors.
 * This fixes off-by-1-pixel-bugs in Rectangle widths and heights.
 */
UT_sint32 GR_Graphics::_tduR(UT_sint32 layoutUnits) const
{
	UT_sint32 idh = tdu(layoutUnits);
	if(tlu(idh) < layoutUnits)
	{
		idh += 1;
	}
	return idh;
}
/*!
 * Create a new image from the Raster rgba byte buffer defined by pBB.
 * The dimensions of iWidth and iHeight are in logical units but the image
 * doesn't scale if the resolution or zoom changes. Instead you must create
 * a new image.
 */
GR_Image* GR_UnixCairoGraphicsBase::createNewImage (const char* pszName,
													const UT_ByteBuf* pBB,
                                                    const std::string& mimetype,
													UT_sint32 iWidth,
													UT_sint32 iHeight,
													GR_Image::GRType iType)
{
   	GR_Image* pImg = NULL;

	if (iType == GR_Image::GRT_Raster) {
		pImg = new GR_UnixImage(pszName);
		pImg->convertFromBuffer(pBB, mimetype, tdu(iWidth), tdu(iHeight));
	} else if (iType == GR_Image::GRT_Vector) {
		pImg = new GR_RSVGVectorImage(pszName);
		pImg->convertFromBuffer(pBB, mimetype, tdu(iWidth), tdu(iHeight));		
	} else {
		UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
	}

   	return pImg;
}
void GR_UnixCairoGraphics::scroll(UT_sint32 x_dest, UT_sint32 y_dest,
						  UT_sint32 x_src, UT_sint32 y_src,
						  G_GNUC_UNUSED UT_sint32 width, G_GNUC_UNUSED UT_sint32 height)
{
#if !GTK_CHECK_VERSION(3,0,0)
	GdkGC *gc;

	disableAllCarets();
	gc = gdk_gc_new(_getWindow());
   	gdk_draw_drawable(_getWindow(), gc, _getWindow(), tdu(x_src), tdu(y_src),
					  tdu(x_dest), tdu(y_dest), tdu(width), tdu(height));
	g_object_unref(G_OBJECT(gc)), gc = NULL;
	enableAllCarets();
#else
	scroll(x_src - x_dest, y_src - y_dest);
#endif
}
/*!
 * This method converts to device units while taking account of the Y-scroll
 * offset. This will always give the exact same logical location on the screen
 * no matter what the Y-scroll offset is. This fixes off-by-1-pixel bugs in Y.
 */
UT_sint32 GR_Graphics::_tduY(UT_sint32 layoutUnits) const
{
	return tdu(layoutUnits+getPrevYOffset()) - tdu(getPrevYOffset());
}