From 1fdc80fbea7ab82c6e2220a964bb957542634323 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Oct 05 2009 07:19:15 +0000 Subject: add complex language fixes --- diff --git a/abiword.spec b/abiword.spec index 7d70ec6..80376be 100644 --- a/abiword.spec +++ b/abiword.spec @@ -7,7 +7,7 @@ Summary: The AbiWord word processor Name: abiword Version: %{majorversion}.%{minorversion}.%{microversion} -Release: 2%{?dist} +Release: 3%{?dist} Epoch: 1 Group: Applications/Editors License: GPLv2+ @@ -34,6 +34,11 @@ Patch3: abiword-plugins-2.6.0-boolean.patch Patch100: abiword-2.6.5-defaultfont.patch Patch101: abiword-2.6.4-draghandles.patch Patch102: abiword-2.6.4-nohtmloptions.patch +Patch200: r27631-bug-12283.patch +Patch201: r27632-mix-roman-and-complex.patch +Patch202: r27655-fix-script-mixing.patch +Patch203: r27656-debug-cleanup.patch +Patch204: r27660-complex-selections.patch %endif BuildRequires: autoconf, libtool @@ -88,6 +93,11 @@ Includes and definitions for developing with libabiword. %patch100 -p1 -b .defaultfont %patch101 -p1 -b .draghandles %patch102 -p1 -b .nohtmloptions +%patch200 -p0 +%patch201 -p0 +%patch202 -p0 +%patch203 -p0 +%patch204 -p0 %endif # setup abiword-plugins @@ -214,6 +224,11 @@ update-desktop-database %{_datadir}/applications %{_libdir}/pkgconfig/%{name}-%{majorversion}.%{minorversion}.pc %changelog +* Thu Sep 24 2009 Daniel Drake - 1:2.6.5-3 +- Add some upstream patches to fix + http://bugzilla.abisource.com/show_bug.cgi?id=12283 and + http://bugzilla.abisource.com/show_bug.cgi?id=12285 + * Wed Dec 03 2008 Marc Maurer - 1:2.6.5-2 - Change the font for Arabic locales to default to DejaVu Sans for better glyph coverage diff --git a/r27631-bug-12283.patch b/r27631-bug-12283.patch new file mode 100644 index 0000000..4ec449b --- /dev/null +++ b/r27631-bug-12283.patch @@ -0,0 +1,323 @@ +Index: src/text/fmt/xp/fl_BlockLayout.cpp +=================================================================== +--- src/text/fmt/xp/fl_BlockLayout.cpp.orig ++++ src/text/fmt/xp/fl_BlockLayout.cpp +@@ -1665,7 +1665,7 @@ void fl_BlockLayout::coalesceRuns(void) + _assertRunListIntegrity(); + + #if 1 +- xxx_UT_DEBUGMSG(("fl_BlockLayout::coalesceRuns\n")); ++ UT_DEBUGMSG(("fl_BlockLayout::coalesceRuns\n")); + fp_Line* pLine = static_cast(getFirstContainer()); + while (pLine) + { +@@ -4894,14 +4894,12 @@ bool fl_BlockLayout::doclistener_populat + return true; + } + +-bool fl_BlockLayout::_doInsertTextSpan(PT_BlockOffset blockOffset, UT_uint32 len) ++bool fl_BlockLayout::itemizeSpan(PT_BlockOffset blockOffset, UT_uint32 len,GR_Itemization & I) + { +- xxx_UT_DEBUGMSG(("_doInsertTextSpan: Initial offset %d, len %d bl_Length %d \n", blockOffset, len,getLength())); + UT_return_val_if_fail( m_pLayout, false ); + PD_StruxIterator text(getStruxDocHandle(), + blockOffset + fl_BLOCK_STRUX_OFFSET, + blockOffset + fl_BLOCK_STRUX_OFFSET + len - 1); +- GR_Itemization I; + I.setDirOverride(m_iDirOverride); + I.setEmbedingLevel(m_iDomDirection); + +@@ -4933,6 +4931,15 @@ bool fl_BlockLayout::_doInsertTextSpan(P + I.setFont(pFont); + + m_pLayout->getGraphics()->itemize(text, I); ++ return true; ++} ++ ++bool fl_BlockLayout::_doInsertTextSpan(PT_BlockOffset blockOffset, UT_uint32 len) ++{ ++ xxx_UT_DEBUGMSG(("_doInsertTextSpan: Initial offset %d, len %d bl_Length %d \n", blockOffset, len,getLength())); ++ GR_Itemization I; ++ bool b= itemizeSpan(blockOffset, len,I); ++ UT_return_val_if_fail( b, false ); + + for(UT_sint32 i = 0; i < static_cast(I.getItemCount()) - 1; ++i) + { +Index: src/text/fmt/xp/fp_TextRun.cpp +=================================================================== +--- src/text/fmt/xp/fp_TextRun.cpp.orig ++++ src/text/fmt/xp/fp_TextRun.cpp +@@ -1108,61 +1108,10 @@ void fp_TextRun::mergeWithNext(void) + + // can only adjust width after the justification has been handled + _setWidth(getWidth() + pNext->getWidth()); +- +- +- // the shaping requirenments of the combined run +- UT_ASSERT( m_pRenderInfo ); +- if(m_pRenderInfo && pNext && pNext->m_pRenderInfo) +- { +- m_pRenderInfo->m_eShapingResult = +- (GRShapingResult)((UT_uint32)m_pRenderInfo->m_eShapingResult +- | (UT_uint32)(pNext-> m_pRenderInfo->m_eShapingResult)); +- +- // because there might be a ligature across the run boundary, we +- // have to refresh +- // get the current refresh state +- GRShapingResult eR = _getRefreshDrawBuffer(); +- eR = (GRShapingResult)((UT_uint32)eR | (UT_uint32)pNext->_getRefreshDrawBuffer()); +- +- if(((UT_uint32) m_pRenderInfo->m_eShapingResult & (UT_uint32)GRSR_Ligatures) != 0) +- { +- // our run contains ligating characters, see if one is at the end +- eR = (GRShapingResult)((UT_uint32)eR | (UT_uint32) GRSR_Ligatures); +- } +- +- _setRefreshDrawBuffer(eR); +- } +- +- +- +- // we need to take into consideration whether this run has been reversed +- // in which case the order of the concating needs to be reversed too +- UT_BidiCharType iVisDirection = getVisDirection(); +- +- bool bReverse = (!s_bBidiOS && iVisDirection == UT_BIDI_RTL) +- || (s_bBidiOS && m_iDirOverride == UT_BIDI_RTL && _getDirection() == UT_BIDI_LTR) +- || (s_bBidiOS && m_iDirOverride == UT_BIDI_LTR && _getDirection() == UT_BIDI_RTL); +- +- UT_uint32 iNextLen = pNext->getLength(); +- UT_uint32 iMyLen = getLength(); +- +- UT_ASSERT( m_pRenderInfo && pNext->m_pRenderInfo); +- if(m_pRenderInfo && pNext->m_pRenderInfo) +- { +- m_pRenderInfo->m_iLength = iMyLen; +- pNext->m_pRenderInfo->m_iLength = iNextLen; +- +- if(!m_pRenderInfo->append(*(pNext->m_pRenderInfo), bReverse)) +- { +- // either the graphics class does not have append capabilities, or the append failed +- // -- we mark the draw buffer for recalculation +- _setRefreshDrawBuffer(GRSR_Unknown); +- } +- +- } +- +- +- _setLength(iMyLen + iNextLen); ++ _setLength(getLength() + pNext->getLength()); ++ DELETEP(m_pRenderInfo); ++ m_pRenderInfo = NULL; ++ itemize(); + _setDirty(isDirty() || pNext->isDirty()); + + setNextRun(pNext->getNextRun(), false); +@@ -1173,28 +1122,12 @@ void fp_TextRun::mergeWithNext(void) + } + + pNext->getLine()->removeRun(pNext, false); +- +- // if appending a strong run onto a weak one, make sure the overall direction +- // is that of the strong run, and tell the line about this, since the call +- // to removeRun above decreased the line's direction counter +- if(!UT_BIDI_IS_STRONG(_getDirection()) && UT_BIDI_IS_STRONG(pNext->_getDirection())) +- { +- _setDirection(pNext->_getDirection()); +- getLine()->addDirectionUsed(_getDirection()); +- } +- else if(UT_BIDI_IS_WEAK(_getDirection()) && UT_BIDI_IS_WEAK(pNext->_getDirection())) +- { +- // numbers will take precedence +- if(UT_BIDI_IS_NUMBER(pNext->_getDirection())) +- { +- _setDirection(pNext->_getDirection()); +- // no need to inform the line, since the visual direction +- // is not going to change +- } +- } ++ lookupProperties(); + setMustClearScreen(); ++ markDrawBufferDirty(); + + delete pNext; ++ + } + + bool fp_TextRun::split(UT_uint32 iSplitOffset) +@@ -1210,10 +1143,6 @@ bool fp_TextRun::split(UT_uint32 iSplitO + + UT_ASSERT(pNew); + +- // when spliting the run, we do not want to recalculated the draw +- // buffer if the current one is up to date +- pNew->_setRefreshDrawBuffer(_getRefreshDrawBuffer()); +- + pNew->_setFont(this->_getFont()); + + pNew->_setDecorations(this->_getDecorations()); +@@ -1263,74 +1192,23 @@ bool fp_TextRun::split(UT_uint32 iSplitO + } + setNextRun(pNew, false); + +- // split the rendering info, this will save us refreshing it +- // which is very expensive (see notes on the mergeWithNext()) +- bool bReverse = ((!s_bBidiOS && iVisDirection == UT_BIDI_RTL) +- || (s_bBidiOS && m_iDirOverride == UT_BIDI_RTL && _getDirection() == UT_BIDI_LTR) +- || (s_bBidiOS && m_iDirOverride == UT_BIDI_LTR && _getDirection() == UT_BIDI_RTL)); +- +- // runs can be split even before any shaping has been done on the, in which case we do not have +- // the redering info yet; in such cases we only have m_pItem +- bool bSplitSucceeded = true; +- +- if(m_pRenderInfo) +- { +- m_pRenderInfo->m_pGraphics = getGraphics(); +- m_pRenderInfo->m_pFont = getFont(); +- m_pRenderInfo->m_iLength = getLength(); +- m_pRenderInfo->m_iOffset = iSplitOffset - getBlockOffset(); +- if(!m_pRenderInfo->split(pNew->m_pRenderInfo, bReverse)) +- { +- // the graphics class is either incapable of spliting, or the operation failed +- // we need to mark both runs for shaping +- _setRefreshDrawBuffer(GRSR_Unknown); +- pNew->_setRefreshDrawBuffer(GRSR_Unknown); +- bSplitSucceeded = false; +- } +- +- +- // the split function created a copy of GR_Item in the render +- // info; bring the member into sync with it (m_pItem is where the GR_Item lives and where it +- // is destroyed) +- if(pNew->m_pRenderInfo) +- { +- pNew->m_pItem = pNew->m_pRenderInfo->m_pItem; +- } +- } +- else +- { +- // if this assert falls, we are in real trouble ... +- UT_ASSERT_HARMLESS( m_pItem ); +- if(m_pItem) +- { +- pNew->m_pItem = m_pItem->makeCopy(); +- } +- } +- +- ++ // reitemize this run and blow away all the old render info. It has to be ++ // recalculated. + +- + setLength(iSplitOffset - getBlockOffset(), false); ++ DELETEP(m_pRenderInfo); ++ itemize(); ++ lookupProperties(); ++ // Reitemize the new run ++ pNew->itemize(); + + if(getLine()) + getLine()->insertRunAfter(pNew, this); + +- // we will use the _addupCharWidths() function here instead of recalcWidth(), since when +- // a run is split the info in the block's char-width array is not affected, so we do not + //have to recalculate these + +- if(bSplitSucceeded) +- { +- _addupCharWidths(); +- pNew->_addupCharWidths(); +- } +- else +- { +- recalcWidth(); +- pNew->recalcWidth(); +- } +- +- ++ recalcWidth(); ++ pNew->recalcWidth(); + + //bool bDomDirection = getBlock()->getDominantDirection(); + +@@ -1345,7 +1223,6 @@ bool fp_TextRun::split(UT_uint32 iSplitO + } + + pNew->_setY(getY()); +- + return true; + } + +@@ -2835,6 +2712,28 @@ UT_sint32 fp_TextRun::getStr(UT_UCSChar + return -1; + } + ++void fp_TextRun::itemize(void) ++{ ++ GR_Itemization I; ++ bool b = getBlock()->itemizeSpan(getBlockOffset(), getLength(),I); ++ UT_return_if_fail(b); ++ // ++ // Should only be one item per run ++ // ++ GR_Item * pItem = I.getNthItem(0)->makeCopy(); ++ UT_return_if_fail(pItem); ++ setItem(pItem->makeCopy()); ++} ++ ++void fp_TextRun::setItem(GR_Item * i) ++{ ++ DELETEP(m_pItem); ++ m_pItem =i; ++ if(m_pRenderInfo) ++ { ++ m_pRenderInfo->m_pItem = m_pItem; ++ } ++} + + void fp_TextRun::setDirection(UT_BidiCharType dir, UT_BidiCharType dirOverride) + { +Index: src/text/fmt/xp/fp_Line.cpp +=================================================================== +--- src/text/fmt/xp/fp_Line.cpp.orig ++++ src/text/fmt/xp/fp_Line.cpp +@@ -3121,8 +3121,12 @@ void fp_Line::coalesceRuns(void) + if (pRun->getType() == FPRUN_TEXT) + { + fp_TextRun* pTR = static_cast(pRun); ++ xxx_UT_DEBUGMSG(("Looking at %d Text run \n",i)); ++ pTR->printText(); + if (pTR->canMergeWithNext()) + { ++ xxx_UT_DEBUGMSG(("Can merge \n")); ++ //pTR->printText(); + fp_Run * pNext = pRun->getNextRun(); + // + // Look if we have a redundant fmtMark. +Index: src/text/fmt/xp/fp_TextRun.h +=================================================================== +--- src/text/fmt/xp/fp_TextRun.h.orig ++++ src/text/fmt/xp/fp_TextRun.h +@@ -108,7 +108,8 @@ public: + | (UT_uint32)eR); + } + +- void setItem(GR_Item * i) {m_pItem = i;} ++ void itemize(void); ++ void setItem(GR_Item * i); + const GR_Item * getItem() const {return m_pItem;} + + +Index: src/text/fmt/xp/fl_BlockLayout.h +=================================================================== +--- src/text/fmt/xp/fl_BlockLayout.h.orig ++++ src/text/fmt/xp/fl_BlockLayout.h +@@ -388,6 +388,8 @@ public: + UT_UTF8String & sWord, + bool bIgnoreSpace); + ++ bool itemizeSpan(PT_BlockOffset blockOffset, UT_uint32 len,GR_Itemization & I); ++ + #ifdef ENABLE_SPELL + /** put in queue for spellchecking after prev. If prev == NULL is put at the head */ + void enqueueToSpellCheckAfter(fl_BlockLayout *prev); diff --git a/r27632-mix-roman-and-complex.patch b/r27632-mix-roman-and-complex.patch new file mode 100644 index 0000000..47182d0 --- /dev/null +++ b/r27632-mix-roman-and-complex.patch @@ -0,0 +1,48 @@ +Index: src/text/fmt/xp/fp_TextRun.cpp +=================================================================== +--- src/text/fmt/xp/fp_TextRun.cpp.orig ++++ src/text/fmt/xp/fp_TextRun.cpp +@@ -1042,6 +1042,8 @@ bool fp_TextRun::canMergeWithNext(void) + && !(*getRevisions() == *(pNext->getRevisions()))) // + //non-null but different + || (pNext->getVisibility() != getVisibility()) ++ // The merge must make just one item ++ || (!isOneItem(pNext)) + + #if 0 + // I do not think this should happen at all +@@ -2712,6 +2714,22 @@ UT_sint32 fp_TextRun::getStr(UT_UCSChar + return -1; + } + ++/*! ++ * Returns if this run plus the next can be combined to make one contiguous ++ * item ++ */ ++bool fp_TextRun::isOneItem(fp_Run * pNext) ++{ ++ GR_Itemization I; ++ bool b = getBlock()->itemizeSpan(getBlockOffset(), getLength()+pNext->getLength(),I); ++ UT_return_val_if_fail(b,false); ++ UT_DEBUGMSG(("Found %d items \n",I.getItemCount()-1)); ++ if(I.getItemCount() <= 2) ++ { ++ return true; ++ } ++ return false; ++} + void fp_TextRun::itemize(void) + { + GR_Itemization I; +Index: src/text/fmt/xp/fp_TextRun.h +=================================================================== +--- src/text/fmt/xp/fp_TextRun.h.orig ++++ src/text/fmt/xp/fp_TextRun.h +@@ -65,6 +65,7 @@ public: + bool canMergeWithNext(void); + void mergeWithNext(void); + bool findFirstNonBlankSplitPoint(fp_RunSplitInfo & splitInfo); ++ bool isOneItem(fp_Run * pNext); + enum + { + Calculate_full_width = -1 diff --git a/r27655-fix-script-mixing.patch b/r27655-fix-script-mixing.patch new file mode 100644 index 0000000..b6ff172 --- /dev/null +++ b/r27655-fix-script-mixing.patch @@ -0,0 +1,80 @@ +Index: src/text/fmt/xp/fp_TextRun.cpp +=================================================================== +--- src/text/fmt/xp/fp_TextRun.cpp (revisión: 27654) ++++ src/text/fmt/xp/fp_TextRun.cpp (revisión: 27655) +@@ -2779,8 +2779,8 @@ + } + + /*! +- * Returns if this run plus the next can be combined to make one contiguous +- * item ++ * Returns true if this run plus the next can be combined to make ++ * one contiguous item + */ + bool fp_TextRun::isOneItem(fp_Run * pNext) + { +@@ -2790,6 +2790,34 @@ + UT_DEBUGMSG(("Found %d items \n",I.getItemCount()-1)); + if(I.getItemCount() <= 2) + { ++ // ++ // Now look to see if there is roman text mixed with ++ // Unicode. Can easily happen with numbers or smart quotes ++ // ++ PD_StruxIterator text(getBlock()->getStruxDocHandle(), ++ getBlockOffset() + fl_BLOCK_STRUX_OFFSET); ++ ++ text.setUpperLimit(text.getPosition() + getLength()+ pNext->getLength() - 1); ++ UT_ASSERT_HARMLESS( text.getStatus() == UTIter_OK ); ++ bool bFoundRoman = false; ++ bool bFoundUnicode = false; ++ while(text.getStatus() == UTIter_OK) ++ { ++ UT_UCS4Char c = text.getChar(); ++ if(c != ' ' && c <256) ++ { ++ bFoundRoman = true; ++ } ++ else if(c!= ' ' && !UT_isSmartQuotedCharacter(c)) ++ { ++ bFoundUnicode = true; ++ } ++ ++text; ++ } ++ if(bFoundRoman && bFoundUnicode) ++ { ++ return false; ++ } + return true; + } + return false; +Index: src/af/util/xp/ut_string.cpp +=================================================================== +--- src/af/util/xp/ut_string.cpp (revisión: 27654) ++++ src/af/util/xp/ut_string.cpp (revisión: 27655) +@@ -802,8 +802,6 @@ + + bool UT_isSmartQuotedCharacter(UT_UCSChar c) + { +- // TODO: this is anglo-centric; really need a locale argument or +- // TODO: something to get smart quote rules for the rest of the world + bool result; + switch (c) + { +@@ -811,6 +809,16 @@ + case UCS_RQUOTE: + case UCS_LDBLQUOTE: + case UCS_RDBLQUOTE: ++ case 0x201a: ++ case 0x201e: ++ case 0x2039: ++ case 0x203a: ++ case 0x300c: ++ case 0x300d: ++ case 0x300e: ++ case 0x300f: ++ case '\"': ++ case '\'': + result = true; + break; + default: diff --git a/r27656-debug-cleanup.patch b/r27656-debug-cleanup.patch new file mode 100644 index 0000000..ad6ae5b --- /dev/null +++ b/r27656-debug-cleanup.patch @@ -0,0 +1,26 @@ +Index: src/text/fmt/xp/fl_BlockLayout.cpp +=================================================================== +--- src/text/fmt/xp/fl_BlockLayout.cpp.orig ++++ src/text/fmt/xp/fl_BlockLayout.cpp +@@ -1665,7 +1665,7 @@ void fl_BlockLayout::coalesceRuns(void) + _assertRunListIntegrity(); + + #if 1 +- UT_DEBUGMSG(("fl_BlockLayout::coalesceRuns\n")); ++ xxx_UT_DEBUGMSG(("fl_BlockLayout::coalesceRuns\n")); + fp_Line* pLine = static_cast(getFirstContainer()); + while (pLine) + { +Index: src/text/fmt/xp/fp_Line.cpp +=================================================================== +--- src/text/fmt/xp/fp_Line.cpp.orig ++++ src/text/fmt/xp/fp_Line.cpp +@@ -3122,7 +3122,7 @@ void fp_Line::coalesceRuns(void) + { + fp_TextRun* pTR = static_cast(pRun); + xxx_UT_DEBUGMSG(("Looking at %d Text run \n",i)); +- pTR->printText(); ++ // pTR->printText(); + if (pTR->canMergeWithNext()) + { + xxx_UT_DEBUGMSG(("Can merge \n")); diff --git a/r27660-complex-selections.patch b/r27660-complex-selections.patch new file mode 100644 index 0000000..8f4aca2 --- /dev/null +++ b/r27660-complex-selections.patch @@ -0,0 +1,107 @@ +Index: src/text/fmt/xp/fp_TextRun.cpp +=================================================================== +--- src/text/fmt/xp/fp_TextRun.cpp.orig ++++ src/text/fmt/xp/fp_TextRun.cpp +@@ -715,7 +715,7 @@ void fp_TextRun::mapXYToPosition(UT_sint + // don't set bBOL to false here + bEOL = false; + } +- ++ pos += adjustCaretPosition(pos,true); + return; + } + +@@ -744,7 +744,7 @@ void fp_TextRun::mapXYToPosition(UT_sint + // the correct place to do it. 2001.02.25 jskov + bEOL = true; + } +- ++ pos += adjustCaretPosition(pos,true); + return; + } + +@@ -779,6 +779,7 @@ void fp_TextRun::mapXYToPosition(UT_sint + + bBOL = false; + bEOL = false; ++ pos += adjustCaretPosition(pos,true); + return; + } + +@@ -812,6 +813,7 @@ void fp_TextRun::mapXYToPosition(UT_sint + iLog = getLength() - i; + + pos = getBlock()->getPosition() + getBlockOffset() + iLog; ++ pos += adjustCaretPosition(pos,true); + return; + } + } +@@ -838,6 +840,7 @@ void fp_TextRun::mapXYToPosition(UT_sint + // reset this, so we have no stale pointers there + m_pRenderInfo->m_pText = NULL; + #endif ++ pos = adjustCaretPosition(pos,true); + return; + } + +@@ -853,18 +856,19 @@ void fp_TextRun::findPointCoords(UT_uint + UT_sint32 yoff2; + UT_sint32 xdiff = 0; + xxx_UT_DEBUGMSG(("findPointCoords: Text Run offset %d \n",iOffset)); +- + if(!m_pRenderInfo || _getRefreshDrawBuffer() == GRSR_Unknown) + { + // this can happen immediately after run is inserted at the + // end of a paragraph. + _refreshDrawBuffer(); + } +- + UT_return_if_fail(m_pRenderInfo); + + UT_return_if_fail(getLine()); + ++ // UT_uint32 docPos = getBlockOffset() + getBlock()->getPosition() +iOffset; ++ //docPos = adjustCaretPosition(docPos,true); ++ //iOffset = docPos - getBlockOffset() + getBlock()->getPosition(); + getLine()->getOffsets(this, xoff, yoff); + + if (m_fPosition == TEXT_POSITION_SUPERSCRIPT) +@@ -3274,9 +3278,10 @@ void fp_TextRun::updateOnDelete(UT_uint3 + + UT_uint32 fp_TextRun::adjustCaretPosition(UT_uint32 iDocumentPosition, bool bForward) + { ++ + UT_uint32 iRunOffset = getBlockOffset() + getBlock()->getPosition(); + +- UT_return_val_if_fail( iDocumentPosition >= iRunOffset && iDocumentPosition < iRunOffset + getLength() && ++ UT_return_val_if_fail( iDocumentPosition >= iRunOffset && iDocumentPosition <= iRunOffset + getLength() && + m_pRenderInfo, + iDocumentPosition); + +@@ -3294,8 +3299,11 @@ UT_uint32 fp_TextRun::adjustCaretPositio + m_pRenderInfo->m_pText = &text; + m_pRenderInfo->m_iOffset = iDocumentPosition - iRunOffset; + m_pRenderInfo->m_iLength = getLength(); +- +- return iRunOffset + getGraphics()->adjustCaretPosition(*m_pRenderInfo, bForward); ++ UT_uint32 adjustedPos = iRunOffset + getGraphics()->adjustCaretPosition(*m_pRenderInfo, bForward); ++ if((adjustedPos - iRunOffset) > getLength()) ++ adjustedPos = iRunOffset + getLength(); ++ _refreshDrawBuffer(); ++ return adjustedPos; + } + + void fp_TextRun::adjustDeletePosition(UT_uint32 &iDocumentPosition, UT_uint32 &iCount) +Index: src/af/gr/unix/gr_UnixPangoGraphics.cpp +=================================================================== +--- src/af/gr/unix/gr_UnixPangoGraphics.cpp.orig ++++ src/af/gr/unix/gr_UnixPangoGraphics.cpp +@@ -2122,7 +2122,7 @@ void GR_UnixPangoGraphics::positionToXY( + // withing range of our string + pOffset = g_utf8_offset_to_pointer (pUtf8, RI.m_iOffset); + } +- else if(i > 1) ++ else if(i >= 1) + { + // this is the case where the requested offset is past the end + // of our string; we will use the last char; as we have more than one