/* AbiWord * Copyright (C) 2004 Tomas Frydrych * * 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_UnixPangoGraphics.h" #include "xap_UnixApp.h" #include "xap_UnixFontManager.h" #include "ut_debugmsg.h" #include "ut_misc.h" #include "xap_App.h" #include "xap_Prefs.h" // need this to include what Pango considers 'low-level' api #define PANGO_ENABLE_ENGINE #include #include UT_uint32 GR_UnixPangoGraphics::s_iInstanceCount = 0; UT_VersionInfo GR_UnixPangoGraphics::s_Version; int GR_UnixPangoGraphics::s_iMaxScript = 0; class GR_UnixPangoItem: public GR_Item { friend class GR_UnixPangoGraphics; public: virtual ~GR_UnixPangoItem(){ if (m_pi) {pango_item_free(m_pi);}}; virtual GR_ScriptType getType() const {return (GR_ScriptType)m_iType;} virtual GR_Item * makeCopy() const { return new GR_UnixPangoItem(pango_item_copy(m_pi)); } virtual GRRI_Type getClassId() const {return GRRI_UNIX_PANGO;} protected: GR_UnixPangoItem(PangoItem *pi); GR_UnixPangoItem() : m_pi(NULL) { }; // just a dummy used to terminate // GR_Itemization list PangoItem *m_pi; UT_uint32 m_iType; }; GR_UnixPangoItem::GR_UnixPangoItem(PangoItem *pi): m_pi(pi) { // there does not seem to be anything that we could use to identify the items, so we // will hash the pointers to the two text engines if(!pi) { m_iType = (UT_uint32)GRScriptType_Void; } else { // there does not seem to be anything that we could use to easily identify the script, so we // will hash the pointers to the two text engines void * b[2]; b[0] = (void*)pi->analysis.shape_engine; b[1] = (void*)pi->analysis.lang_engine; m_iType = UT_hash32((const char *) &b, 2 * sizeof(void*)); } } class GR_UnixPangoRenderInfo : public GR_RenderInfo { public: GR_UnixPangoRenderInfo(GR_ScriptType t): GR_RenderInfo(t), m_pGlyphs(NULL), m_pJustify(NULL) { ++s_iInstanceCount; }; virtual ~GR_UnixPangoRenderInfo() { delete [] m_pJustify; s_iInstanceCount--; if(!s_iInstanceCount) { delete [] s_pLogAttr; s_pLogAttr = NULL; } }; virtual GRRI_Type getType() const {return GRRI_UNIX_PANGO;} 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; bool getUTF8Text(); inline bool allocStaticBuffers(UT_uint32 iSize) { if(s_pLogAttr) { delete [] s_pLogAttr; s_pLogAttr = NULL; } s_pLogAttr = new PangoLogAttr[iSize]; // log attr. correspont to characters, not glyphs, but since there are // always at least as many glyphs, this is OK UT_return_val_if_fail(s_pLogAttr, false); s_iStaticSize = iSize; s_pOwnerUTF8 = NULL; return true; } PangoGlyphString* m_pGlyphs; int * m_pJustify; static UT_UTF8String sUTF8; static GR_UnixPangoRenderInfo * s_pOwnerUTF8; static PangoLogAttr * s_pLogAttr; static UT_uint32 s_iInstanceCount; static UT_uint32 s_iStaticSize; // size of the static buffers }; GR_UnixPangoRenderInfo * GR_UnixPangoRenderInfo::s_pOwnerUTF8 = NULL; UT_UTF8String GR_UnixPangoRenderInfo::sUTF8; PangoLogAttr * GR_UnixPangoRenderInfo::s_pLogAttr = NULL; UT_uint32 GR_UnixPangoRenderInfo::s_iInstanceCount = 0; UT_uint32 GR_UnixPangoRenderInfo::s_iStaticSize = 0; bool GR_UnixPangoRenderInfo::getUTF8Text() { if(s_pOwnerUTF8 == this) return true; UT_return_val_if_fail( m_pText, false ); UT_TextIterator & text = *m_pText; sUTF8.clear(); for(; text.getStatus() == UTIter_OK; ++text) { sUTF8 += text.getChar(); } s_pOwnerUTF8 = this; return true; } GR_UnixPangoGraphics::GR_UnixPangoGraphics(GdkWindow * win, XAP_UnixFontManager * fontManager, XAP_App *app) :GR_UnixGraphics(win, fontManager, app), m_pFontMap(NULL),m_pContext(NULL), m_pFont(NULL) { UT_DEBUGMSG(("GR_UnixPangoGraphics::GR_UnixPangoGraphics using pango (window)\n")); GdkDisplay * gDisp = gdk_drawable_get_display(win); GdkScreen * gScreen = gdk_drawable_get_screen(win); Display * disp = GDK_DISPLAY_XDISPLAY(gDisp); int iScreen = gdk_x11_screen_get_screen_number(gScreen); m_pContext = gdk_pango_context_get_for_screen(gScreen); m_pFontMap = pango_xft_get_font_map(disp, iScreen); } GR_UnixPangoGraphics::GR_UnixPangoGraphics(GdkPixmap * win, XAP_UnixFontManager * fontManager, XAP_App *app, bool bUsePixmap) :GR_UnixGraphics(win, fontManager, app, bUsePixmap), m_pFontMap(NULL),m_pContext(NULL), m_pFont(NULL) { UT_DEBUGMSG(("GR_UnixPangoGraphics::GR_UnixPangoGraphics using pango (pixmap)\n")); // this is wrong, need context for the printer UT_ASSERT_HARMLESS( 0 ); GdkDisplay * gDisp = gdk_drawable_get_display(win); GdkScreen * gScreen = gdk_drawable_get_screen(win); Display * disp = GDK_DISPLAY_XDISPLAY(gDisp); int iScreen = gdk_x11_screen_get_screen_number(gScreen); m_pContext = gdk_pango_context_get_for_screen(gScreen); m_pFontMap = pango_xft_get_font_map(disp, iScreen); } GR_UnixPangoGraphics::~GR_UnixPangoGraphics() { } GR_Graphics * GR_UnixPangoGraphics::graphicsAllocator(GR_AllocInfo& info) { UT_return_val_if_fail(info.getType() == GRID_UNIX, NULL); UT_DEBUGMSG(("GR_UnixPangoGraphics::graphicsAllocator\n")); GR_UnixAllocInfo &AI = (GR_UnixAllocInfo&)info; //!!!WDG might be right if(AI.m_usePixmap || AI.m_pixmap) { // printer graphics required return new GR_UnixPangoGraphics(AI.m_pixmap, AI.m_fontManager, XAP_App::getApp(),AI.m_usePixmap); } else { // screen graphics required return new GR_UnixPangoGraphics(AI.m_win, AI.m_fontManager, XAP_App::getApp()); } } bool GR_UnixPangoGraphics::itemize(UT_TextIterator & text, GR_Itemization & I) { // Performance is not of the highest priorty, as this function gets only called once // on each text fragment on load or keyboard entry UT_DEBUGMSG(("GR_UnixPangoGraphics::itemize\n")); UT_return_val_if_fail( m_pContext, false ); // we need to convert our ucs4 data to utf8 for pango UT_UTF8String utf8; 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 UT_uint32 i; for(i = 0; i < iLen; ++i, ++text) { UT_return_val_if_fail(text.getStatus() == UTIter_OK, false); utf8 += text.getChar(); } UT_uint32 iItemCount; // PangoAttrList *pAttr = pango_attr_list_new(); GList *gItems = pango_itemize(m_pContext, utf8.utf8_str(), 0, utf8.byteLength(), NULL, NULL); iItemCount = g_list_length(gItems); //!!!WDG haven't decided what to do about attributes yet // We do not want to use these attributes, because the text we draw in a single call // is always homogenous // pango_attr_list_unref(pAttr); // now we process the ouptut UT_DEBUGMSG(("itemize: number of items %d\n", iItemCount)); for(i = 0; i < iItemCount; ++i) { UT_DEBUGMSG(("itemize: creating item %d\n", i)); PangoItem *pItem = (PangoItem *)g_list_nth(gItems, i)->data; GR_UnixPangoItem * pI = new GR_UnixPangoItem(pItem); UT_return_val_if_fail(pI, false); I.addItem(pItem->offset, pI); } I.addItem(iPosEnd - iPosStart + 1, new GR_UnixPangoItem()); UT_DEBUGMSG(("itemize succeeded\n")); return true; } bool GR_UnixPangoGraphics::shape(GR_ShapingInfo & si, GR_RenderInfo *& ri) { UT_DEBUGMSG(("GR_UnixPangoGraphics::shape\n")); UT_return_val_if_fail(si.m_pItem && si.m_pItem->getClassId() == GRRI_UNIX_PANGO && si.m_pFont, false); GR_UnixPangoItem * pItem = (GR_UnixPangoItem *)si.m_pItem; if(!ri) { // this simply allocates new instance of the RI which this function will fill with // meaningful data ri = new GR_UnixPangoRenderInfo(pItem->getType()); UT_return_val_if_fail(ri, false); } else { UT_return_val_if_fail(ri->getType() == GRRI_UNIX_PANGO, false); } GR_UnixPangoRenderInfo * RI = (GR_UnixPangoRenderInfo *)ri; UT_UTF8String utf8; UT_sint32 i; for(i = 0; i < si.m_iLength; ++i, ++si.m_Text) { UT_return_val_if_fail(si.m_Text.getStatus() == UTIter_OK, false); utf8 += si.m_Text.getChar(); } if(RI->m_pGlyphs) { pango_glyph_string_free(RI->m_pGlyphs); } RI->m_pGlyphs = pango_glyph_string_new(); // !!!WDG where to get gtext and glength from ??? - the GR_ShapingInfo? // The text is in pInChars, conversion to utf-8 and removal for m_text from the item // is probably desirable // before we can call this, we have to set analysis.font // Is this the case, or is the font set by pango_itemize()? #TF GR_UnixPangoFont * pFont = (GR_UnixPangoFont *) si.m_pFont; pItem->m_pi->analysis.font = pFont->getPangoFont(); pango_shape(utf8.utf8_str(), utf8.byteLength(), &(pItem->m_pi->analysis), RI->m_pGlyphs); // need to transfer data that we will need later from si to RI RI->m_iLength = si.m_iLength; RI->m_pItem = si.m_pItem; RI->m_pFont = si.m_pFont; RI->m_eShapingResult = GRSR_ContextSensitiveAndLigatures; return true; } UT_sint32 GR_UnixPangoGraphics::getTextWidth(const GR_RenderInfo & ri) const { UT_DEBUGMSG(("GR_UnixPangoGraphics::getTextWidth\n")); UT_return_val_if_fail(ri.getType() == GRRI_UNIX_PANGO, 0); GR_UnixPangoRenderInfo & RI = (GR_UnixPangoRenderInfo &)ri; UT_return_val_if_fail( RI.m_pGlyphs, 0 ); GR_UnixPangoFont * pFont = (GR_UnixPangoFont *) RI.m_pFont; UT_return_val_if_fail( pFont, 0 ); PangoFont * pf = pFont->getPangoFont(); UT_return_val_if_fail( pf, 0 ); UT_sint32 iWidth = 0; PangoRectangle IR, LR; // need to convert the char offset and length to glyph offsets UT_uint32 iGlyphCount = RI.m_pGlyphs->num_glyphs; UT_sint32 iOffsetStart = -1, iOffsetEnd = -1; for(UT_uint32 i = 0; i < iGlyphCount; ++i) { if(iOffsetStart < 0 && RI.m_pGlyphs->log_clusters[i] == RI.m_iOffset) { iOffsetStart = i; continue; } if(iOffsetEnd < 0 && RI.m_pGlyphs->log_clusters[i] == RI.m_iOffset + RI.m_iLength) { iOffsetEnd = i; break; } } UT_return_val_if_fail( iOffsetStart >= 0, 0 ); if(iOffsetEnd < 0) { // to the end iOffsetEnd = iGlyphCount; } pango_glyph_string_extents_range(RI.m_pGlyphs, iOffsetStart, iOffsetEnd, pf, &IR, &LR); iWidth = tlu(IR.width) / PANGO_SCALE; return iWidth; } void GR_UnixPangoGraphics::prepareToRenderChars(GR_RenderInfo & ri) { } /*! The offset passed to us as part of ri is a visual offset */ void GR_UnixPangoGraphics::renderChars(GR_RenderInfo & ri) { UT_DEBUGMSG(("GR_UnixPangoGraphics::renderChars\n")); UT_return_if_fail(ri.getType() == GRRI_UNIX_PANGO); GR_UnixPangoRenderInfo & RI = (GR_UnixPangoRenderInfo &)ri; GR_UnixPangoFont * pFont = (GR_UnixPangoFont *)RI.m_pFont; GR_UnixPangoItem * pItem = (GR_UnixPangoItem *)RI.m_pItem; UT_return_if_fail(pItem && pFont && pFont->getPangoFont()); if(RI.m_iLength == 0) return; UT_DEBUGMSG(("renderChars: xoff %d yoff %d\n", RI.m_xoff, RI.m_yoff)); UT_sint32 xoff = _tduX(RI.m_xoff); UT_sint32 yoff = _tduY(RI.m_yoff); UT_DEBUGMSG(("about to pango_xft_render xoff %d yoff %d\n", xoff, yoff)); UT_return_if_fail(m_pXftDraw && RI.m_pGlyphs); pango_xft_render(m_pXftDraw, &m_XftColor, pFont->getPangoFont(), RI.m_pGlyphs, xoff, yoff); } void GR_UnixPangoGraphics::measureRenderedCharWidths(GR_RenderInfo & ri) { // !!!WDG pango doesn't do scriptplace - I think it is part of pango_shape // not sure what is to be done here? // OK, in that case we do nothing, the measure call is always subsequent to the shape // call #TF } void GR_UnixPangoGraphics::appendRenderedCharsToBuff(GR_RenderInfo & ri, UT_GrowBuf & buf) const { UT_return_if_fail( UT_NOT_IMPLEMENTED ); } /*! returns true on success */ bool GR_UnixPangoGraphics::_scriptBreak(GR_UnixPangoRenderInfo &ri) { UT_return_val_if_fail(ri.m_pText && ri.m_pGlyphs && ri.m_pItem, false); GR_UnixPangoItem * pItem = (GR_UnixPangoItem*)ri.m_pItem; // fill the static buffer with UTF8 text UT_return_val_if_fail(ri.getUTF8Text(), false); UT_return_val_if_fail(ri.allocStaticBuffers(ri.m_pGlyphs->num_glyphs), false); pango_break(ri.sUTF8.utf8_str(), ri.sUTF8.byteLength(),&(pItem->m_pi->analysis), ri.s_pLogAttr, ri.m_pGlyphs->num_glyphs); return true; } bool GR_UnixPangoGraphics::canBreak(GR_RenderInfo & ri, UT_sint32 &iNext, bool bAfter) { UT_return_val_if_fail(ri.getType() == GRRI_UNIX_PANGO && ri.m_iOffset < ri.m_iLength, false); GR_UnixPangoRenderInfo & RI = (GR_UnixPangoRenderInfo &)ri; iNext = -1; if(!_scriptBreak(RI)) return false; if(ri.m_iLength > (UT_sint32)RI.s_iStaticSize) { UT_return_val_if_fail( RI.allocStaticBuffers(ri.m_iLength),false ); } UT_uint32 iDelta = 0; 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; } if(RI.s_pLogAttr[ri.m_iOffset + iDelta].is_char_break) 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].is_char_break) { iNext = i - iDelta; break; } } return false; } UT_sint32 GR_UnixPangoGraphics::resetJustification(GR_RenderInfo & ri, bool bPermanent) { UT_return_val_if_fail(ri.getType() == GRRI_UNIX_PANGO, 0); GR_UnixPangoRenderInfo & RI = (GR_UnixPangoRenderInfo &)ri; UT_sint32 iWidth2 = 0; for(UT_sint32 i = 0; i < RI.m_pGlyphs->num_glyphs; ++i) { iWidth2 += RI.m_pJustify[i]; } if(bPermanent) { delete [] RI.m_pJustify; RI.m_pJustify = NULL; } else { memset(RI.m_pJustify, 0, RI.m_pGlyphs->num_glyphs * sizeof(int)); } return -iWidth2; } UT_sint32 GR_UnixPangoGraphics::countJustificationPoints(const GR_RenderInfo & ri) const { UT_return_val_if_fail(ri.getType() == GRRI_UNIX_PANGO, 0); GR_UnixPangoRenderInfo & RI = (GR_UnixPangoRenderInfo &)ri; UT_return_val_if_fail(RI.m_pText, 0); UT_TextIterator & text = *RI.m_pText; UT_uint32 iPosEnd = text.getUpperLimit(); text.setPosition(iPosEnd); UT_return_val_if_fail( text.getStatus()== UTIter_OK, 0 ); UT_sint32 iCount = 0; bool bNonBlank = false; for(; text.getStatus() == UTIter_OK; --text) { UT_UCS4Char c = text.getChar(); if(c != UCS_SPACE) { bNonBlank = true; continue; } // only count this space if this is not last run, or if we // have found something other than spaces if(!ri.m_bLastOnLine || bNonBlank) iCount++; } if(!bNonBlank) { return -iCount; } else { return iCount; } } /*! We take the same approach as with Uniscribe; we store the justification amount in a separate array of the ri and add it to the offsets before we draw. We will probably need some static buffers to speed things up */ void GR_UnixPangoGraphics::justify(GR_RenderInfo & ri) { UT_return_if_fail(ri.getType() == GRRI_UNIX_PANGO); GR_UnixPangoRenderInfo & RI = (GR_UnixPangoRenderInfo &) ri; if(!RI.m_iJustificationPoints || !RI.m_iJustificationAmount || !RI.m_pGlyphs) return; if(!RI.m_pJustify) RI.m_pJustify = new int[RI.m_pGlyphs->num_glyphs]; UT_return_if_fail(RI.m_pJustify); memset(RI.m_pJustify, 0, RI.m_pGlyphs->num_glyphs * sizeof(int)); UT_uint32 iExtraSpace = RI.m_iJustificationAmount; UT_uint32 iPoints = RI.m_iJustificationPoints; UT_return_if_fail( RI.m_pText ); UT_TextIterator & text = *RI.m_pText; for(UT_sint32 i = 0; text.getStatus() == UTIter_OK && i < RI.m_iLength; ++text, ++i) { UT_UCS4Char c = text.getChar(); if(c == UCS_SPACE) { UT_uint32 iSpace = iExtraSpace/iPoints; iExtraSpace -= iSpace; iPoints--; RI.m_pJustify[i] = iSpace; if(!iPoints) break; } } UT_ASSERT_HARMLESS( !iExtraSpace ); } UT_uint32 GR_UnixPangoGraphics::XYToPosition(const GR_RenderInfo & ri, UT_sint32 x, UT_sint32 y) const { UT_return_val_if_fail(ri.getType() == GRRI_UNIX_PANGO, 0); GR_UnixPangoRenderInfo & RI = (GR_UnixPangoRenderInfo &) ri; GR_UnixPangoItem * pItem = (GR_UnixPangoItem *)RI.m_pItem; UT_return_val_if_fail(pItem, 0); UT_return_val_if_fail( UT_NOT_IMPLEMENTED, 0 ); } void GR_UnixPangoGraphics::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_UNIX_PANGO); GR_UnixPangoRenderInfo & RI = (GR_UnixPangoRenderInfo &) ri; GR_UnixPangoItem * pItem = (GR_UnixPangoItem *)RI.m_pItem; if(!pItem) return; // TODO: this is very inefficient: to cache or not to cache ? UT_UTF8String utf8; UT_sint32 i; for(i = 0; i < RI.m_iLength; ++i, ++(*(RI.m_pText))) { UT_return_if_fail(RI.m_pText->getStatus() == UTIter_OK); utf8 += RI.m_pText->getChar(); } pango_glyph_string_index_to_x (RI.m_pGlyphs, (char*)utf8.utf8_str(), // do not like this ... utf8.byteLength(), &(pItem->m_pi->analysis), RI.m_iOffset, RI.m_bLastOnLine, &x); x = x; x2 = x; } void GR_UnixPangoGraphics::drawChars(const UT_UCSChar* pChars, int iCharOffset, int iLength, UT_sint32 xoff, UT_sint32 yoff, int * pCharWidth) { UT_return_if_fail(m_pXftDraw); UT_UTF8String utf8(pChars + iCharOffset, iLength); // this function expect indexes in bytes !!! (stupid) GList * pItems = pango_itemize(getContext(), utf8.utf8_str(), 0, utf8.byteLength(), NULL, NULL); int iItemCount = g_list_length(pItems); PangoGlyphString * pGstring = pango_glyph_string_new(); UT_sint32 xoffD = _tduX(xoff); UT_sint32 yoffD = _tduY(yoff); PangoFont * pf = m_pFont->getPangoFont(); PangoRectangle IR, LR; for(int i = 0; i < iItemCount; ++i) { PangoItem *pItem = (PangoItem *)g_list_nth(pItems, i)->data; UT_return_if_fail( pItem ); pItem->analysis.font = pf; pango_shape(utf8.utf8_str()+ pItem->offset, pItem->length, &(pItem->analysis), pGstring); pango_xft_render(m_pXftDraw, &m_XftColor, pf, pGstring, xoffD, yoffD); // now advance xoff pango_glyph_string_extents(pGstring, pf, &IR, &LR); xoffD += PANGO_PIXELS(IR.width); } pango_glyph_string_free(pGstring); } void GR_UnixPangoGraphics::setFont(GR_Font * pFont) { UT_return_if_fail( pFont ); //PangoFont * pf = (PangoFont*) pFont; m_pFont = (GR_UnixPangoFont *)pFont; } GR_Font* GR_UnixPangoGraphics::getDefaultFont(UT_String& fontFamily) { UT_return_val_if_fail( UT_NOT_IMPLEMENTED, NULL ); } const char* GR_Graphics::findNearestFont(const char* pszFontFamily, const char* pszFontStyle, const char* pszFontVariant, const char* pszFontWeight, const char* pszFontStretch, const char* pszFontSize) { return pszFontFamily; } UT_uint32 GR_UnixPangoGraphics::getFontAscent() { return getFontAscent(m_pFont); } UT_uint32 GR_UnixPangoGraphics::getFontDescent() { return getFontDescent(m_pFont); } UT_uint32 GR_UnixPangoGraphics::getFontHeight() { return getFontHeight(m_pFont); } UT_uint32 GR_UnixPangoGraphics::getFontAscent(GR_Font * pFont) { UT_return_val_if_fail( pFont, 0 ); GR_UnixPangoFont * pFP = (GR_UnixPangoFont*) pFont; PangoFont * pf = pFP->getPangoFont(); // FIXME: we probably want the real language from somewhere PangoFontMetrics * pfm = pango_font_get_metrics(pf, pango_language_from_string("en-US")); UT_return_val_if_fail( pfm, 0 ); pango_font_metrics_unref(pfm); return (UT_uint32) pango_font_metrics_get_ascent(pfm); } UT_uint32 GR_UnixPangoGraphics::getFontDescent(GR_Font *pFont) { UT_return_val_if_fail( pFont, 0 ); GR_UnixPangoFont * pFP = (GR_UnixPangoFont*) pFont; PangoFont * pf = pFP->getPangoFont(); // FIXME: we probably want the real language from somewhere PangoFontMetrics * pfm = pango_font_get_metrics(pf, pango_language_from_string("en-US")); UT_return_val_if_fail( pfm, 0 ); pango_font_metrics_unref(pfm); return (UT_uint32) pango_font_metrics_get_descent(pfm); } UT_uint32 GR_UnixPangoGraphics::getFontHeight(GR_Font *pFont) { UT_return_val_if_fail( pFont, 0 ); GR_UnixPangoFont * pFP = (GR_UnixPangoFont*) pFont; PangoFont * pf = pFP->getPangoFont(); // FIXME: we probably want the real language from somewhere PangoFontMetrics * pfm = pango_font_get_metrics(pf, pango_language_from_string("en-US")); UT_return_val_if_fail( pfm, 0 ); pango_font_metrics_unref(pfm); return (UT_uint32) (pango_font_metrics_get_ascent(pfm) + pango_font_metrics_get_descent(pfm)); } GR_Font* GR_UnixPangoGraphics::_findFont(const char* pszFontFamily, const char* pszFontStyle, const char* pszFontVariant, const char* pszFontWeight, const char* pszFontStretch, const char* pszFontSize) { UT_String s = pszFontFamily; s += " "; s += pszFontStyle; s += " "; s += pszFontVariant; s += " "; s += pszFontWeight; s += " "; s += pszFontStretch; s += " "; s += pszFontSize; PangoFontDescription * pfd = pango_font_description_from_string(s.c_str()); UT_return_val_if_fail( pfd, NULL ); return new GR_UnixPangoFont(pfd, this); } void GR_UnixPangoGraphics::getCoverage(UT_NumberVector& coverage) { // I am not sure if this is really used for anything, my grep indicates no UT_ASSERT_HARMLESS( UT_NOT_IMPLEMENTED ); } //////////////////////////////////////////////////////////////////////////////////////////////////// // // GR_UnixPangFont implementation // GR_UnixPangoFont::GR_UnixPangoFont(PangoFontDescription * pDesc, GR_UnixPangoGraphics * pG) :m_pf(NULL) { UT_return_if_fail( pDesc && pG ); m_pf = pango_context_load_font(pG->getContext(), pDesc); } /*! Measure the unremapped char to be put into the cache. That means measuring it for a font size of 120 */ UT_sint32 GR_UnixPangoFont::measureUnremappedCharForCache(UT_UCS4Char cChar) const { // this is not implemented because we do not use the width cache (when shaping, it is // not possible to measure characters, only glyphs) UT_ASSERT_HARMLESS( UT_NOT_IMPLEMENTED ); return 0; } /* NB: it is essential that this function is fast */ bool GR_UnixPangoFont::doesGlyphExist(UT_UCS4Char g) { UT_return_val_if_fail( m_pf, false ); // FIXME: need to pass the real language down to this function eventually, but since // we only expect answer in yes/no terms, this will do quite well for now PangoCoverage* pCoverage = pango_font_get_coverage(m_pf, pango_language_from_string("en-US")); UT_return_val_if_fail( pCoverage, false ); PangoCoverageLevel eLevel = pango_coverage_get(pCoverage, g); if(PANGO_COVERAGE_NONE == eLevel) return false; return true; } bool GR_UnixPangoFont::glyphBox(UT_UCS4Char g, UT_Rect & rec) const { UT_ASSERT_HARMLESS( UT_NOT_IMPLEMENTED ); return false; } ////////////////////////////////////////////////////////////////////////////// // // GR_UnixPangoRenderInfo Implementation // bool GR_UnixPangoRenderInfo::append(GR_RenderInfo &ri, bool bReverse) { //UT_return_val_if_fail( UT_NOT_IMPLEMENTED, false ); return false; } bool GR_UnixPangoRenderInfo::split (GR_RenderInfo *&pri, bool bReverse) { UT_return_val_if_fail(m_pGraphics && m_pFont, false); UT_ASSERT_HARMLESS(!pri); // create a new RI and make a copy of item into if(!pri) { pri = new GR_UnixPangoRenderInfo(m_eScriptType); UT_return_val_if_fail(pri,false); } pri->m_pItem = m_pItem->makeCopy(); UT_return_val_if_fail(pri->m_pItem, false); return false; } bool GR_UnixPangoRenderInfo::cut(UT_uint32 offset, UT_uint32 iLen, bool bReverse) { return false; } bool GR_UnixPangoRenderInfo::isJustified() const { UT_return_val_if_fail( UT_NOT_IMPLEMENTED,false ); } GR_UnixPangoFont::~GR_UnixPangoFont() { }