HI,
        Abi's underlining code has a bug that has been bothering me for a
while. To see it.

1. Take a string of text.
2. Go to superscript mode and insert text.
3. Underline the original text and the superscript text.

The underline moves up underneath the superscript text. This almost always
not what you want which would be to have the underline continue along
underneath the superscript at the same level as the underline of the
original text. Further more if the height of the original text is large
enough to trigger a change of the width of the underline the underline
under the superscript may be thinner. There is a similar bug for overline
too - which is actually how I noticed the problem.

After some thought I believe that what a user typically wants is a single
straight line underneath all the text included in an underline.

Fixing this bug meant a substantial enlargment of the fp_run.* and
fp_textrun.* code since it is only possible to know where to put an
underline AFTER an underline (or overline) is specified. The underline
could easily extend of a number of text runs. So now underlines are only
drawn after a underline is completed. In the case where an underline is
not drawn the NEXT text run is marked as dirty for a redraw until the end
of the underline is completed.

This code is only for the cross platform display presently. I will fix the
Unix printing code shortly to include this new behaviour.

Cheers

Martin

diff -Naur --exclude=CVS --exclude=fv_View.h --exclude=fv_View.cpp 
--exclude=fl_BlockLayout.cpp --exclude=fp_Line.cpp abi/src/text/fmt/xp/fp_Run.cpp 
abi-new/src/text/fmt/xp/fp_Run.cpp
--- abi/src/text/fmt/xp/fp_Run.cpp      Sat Feb 12 11:40:50 2000
+++ abi-new/src/text/fmt/xp/fp_Run.cpp  Sat Mar 18 06:00:05 2000
@@ -77,6 +77,7 @@
        m_iDescent = 0;
        m_iAscentLayoutUnits = 0;
        m_iDescentLayoutUnits = 0;
+        m_iLinethickness = 0;
 }
 
 fp_Run::~fp_Run()
@@ -270,6 +271,58 @@
 
        return pSpanAP;
 }
+
+void fp_Run::setLinethickness(UT_sint32 max_linethickness)
+{
+         m_iLinethickness = max_linethickness;
+}
+
+UT_sint32 fp_Run::getLinethickness( void)
+{
+         return m_iLinethickness;
+}
+
+void fp_Run::setUnderlineXoff(UT_sint32 xoff)
+{
+         m_iUnderlineXoff = xoff;
+}
+
+UT_sint32 fp_Run::getUnderlineXoff(void)
+{
+         return m_iUnderlineXoff;
+}
+
+void fp_Run::setOverlineXoff(UT_sint32 xoff)
+{
+         m_iOverlineXoff = xoff;
+}
+
+UT_sint32 fp_Run::getOverlineXoff(void)
+{
+         return m_iOverlineXoff;
+}
+
+void fp_Run::setMaxUnderline(UT_sint32 maxh)
+{
+         m_imaxUnderline = maxh;
+}
+
+UT_sint32 fp_Run::getMaxUnderline(void)
+{
+         return m_imaxUnderline;
+}
+
+void fp_Run::setMinOverline(UT_sint32 minh)
+{
+         m_iminOverline = minh;
+}
+
+UT_sint32 fp_Run::getMinOverline(void)
+{
+         return m_iminOverline;
+}
+
+
 
 //////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////
diff -Naur --exclude=CVS --exclude=fv_View.h --exclude=fv_View.cpp 
--exclude=fl_BlockLayout.cpp --exclude=fp_Line.cpp abi/src/text/fmt/xp/fp_Run.h 
abi-new/src/text/fmt/xp/fp_Run.h
--- abi/src/text/fmt/xp/fp_Run.h        Sat Feb 12 11:40:50 2000
+++ abi-new/src/text/fmt/xp/fp_Run.h    Sat Mar 18 05:20:55 2000
@@ -150,7 +150,20 @@
        virtual UT_Bool                 doesContainNonBlankData(void) const { return 
UT_TRUE; } // Things like text whould return false if it is all spaces.
        virtual UT_Bool                 isSuperscript(void) const { return UT_FALSE; }
        virtual UT_Bool                 isSubscript(void) const { return UT_FALSE; }
-
+       virtual UT_Bool                 isUnderline(void) const { return UT_FALSE; }
+       virtual UT_Bool                 isOverline(void) const { return UT_FALSE; }
+       virtual UT_Bool                 isStrikethrough(void) const { return UT_FALSE; 
+}
+       virtual void                    setLinethickness( UT_sint32 
+max_linethickness);
+        virtual UT_sint32               getLinethickness( void);
+       virtual void                    setUnderlineXoff(UT_sint32 xoff);
+       virtual UT_sint32               getUnderlineXoff(void);
+       virtual void                    setOverlineXoff(UT_sint32 xoff);
+       virtual UT_sint32               getOverlineXoff(void);
+       virtual void                    setMaxUnderline(UT_sint32 xoff);
+       virtual UT_sint32               getMaxUnderline(void);
+       virtual void                    setMinOverline(UT_sint32 xoff);
+       virtual UT_sint32               getMinOverline(void);
+       
 #ifdef FMT_TEST
        virtual void                    __dump(FILE * fp) const;
 #endif 
@@ -173,6 +186,11 @@
        UT_uint32                               m_iDescent;
        UT_uint32                               m_iAscentLayoutUnits;
        UT_uint32                               m_iDescentLayoutUnits;
+        UT_sint32                               m_iLinethickness;
+        UT_sint32                               m_iUnderlineXoff;
+        UT_sint32                               m_imaxUnderline;
+        UT_sint32                               m_iminOverline;
+        UT_sint32                               m_iOverlineXoff;
        GR_Graphics*            m_pG;
        UT_Bool                                 m_bDirty;               // run erased 
@ old coords, needs to be redrawn
 };
diff -Naur --exclude=CVS --exclude=fv_View.h --exclude=fv_View.cpp 
--exclude=fl_BlockLayout.cpp --exclude=fp_Line.cpp abi/src/text/fmt/xp/fp_TextRun.cpp 
abi-new/src/text/fmt/xp/fp_TextRun.cpp
--- abi/src/text/fmt/xp/fp_TextRun.cpp  Sat Jan 29 00:51:34 2000
+++ abi-new/src/text/fmt/xp/fp_TextRun.cpp      Sat Mar 18 05:27:49 2000
@@ -951,37 +951,166 @@
          Upon entry to this function, yoff is the TOP of the run,
          NOT the baseline.
        */
-       
-       /*
-         TODO I *think* this line width should be proportional
-         to the size of the font.
-       */
+
+     /*
+       Here is the code to work out the position and thickness of under
+        and overlines for a run of text. This is neccessary because an
+underline or overline could shift position depending on the text size -
+particularly for subscripts and superscripts. We can't work out where to put 
+the lines until the end of the lined span. This info is saved in the fp_Run
+classes. If a underline or overline is pending (because the next run continues
+ the underline or overline), mark the next run as dirty to make sure it is
+drawn.
+     */
+
+  if( (m_fDecorations & (TEXT_DECOR_UNDERLINE | TEXT_DECOR_OVERLINE | 
+                       TEXT_DECOR_LINETHROUGH)) == 0) return;
         UT_sint32 old_LineWidth = m_iLineWidth;
-       m_iLineWidth = 1 + (UT_MAX(10,getAscent()) - 10)/8;
+        UT_sint32 cur_linewidth = 1+ (UT_MAX(10,m_iAscent)-10)/8;
+       UT_sint32 iDrop = 0;
+        fp_Run* P_Run = getPrev();
+        fp_Run* N_Run = getNext();
+        UT_Bool b_Underline = isUnderline();
+        UT_Bool b_Overline = isOverline();
+       UT_Bool b_Strikethrough = isStrikethrough();
 
+       /*
+         If the previous run is NULL, we are on the first run of the line
+so set the linethickness, start of the line span and the overline and underline
+positions from the current measurements.
+       */
+        if(P_Run == NULL)
+       {
+               setLinethickness(cur_linewidth);
+               if(b_Underline)
+               {
+                    iDrop = yoff + m_iAscent + m_iDescent/3;
+                    setUnderlineXoff( xoff);
+                    setMaxUnderline(iDrop);
+               }
+               if(b_Overline)
+               {
+                    iDrop = yoff + (UT_MAX(10,m_iAscent) - 10)/8;
+                    setOverlineXoff( xoff);
+                    setMinOverline(iDrop);
+               }
+       }
+       /*
+         Otherwise look to see if the previous run had an underline or 
+overline. If it does, merge the information with the present information. Take
+the Maximum of the underline offsets and the minimum of the overline offsets.
+Always take the maximum of the linewidths. If there is no previous underline
+or overline set the underline and overline locations with the current data.
+       */
+       else
+       {
+         if (!P_Run->isUnderline() && !P_Run->isOverline() && 
+             !P_Run->isStrikethrough())
+             {
+                    setLinethickness(cur_linewidth);
+             }
+             else
+             {
+                    
+setLinethickness(UT_MAX(P_Run->getLinethickness(),cur_linewidth));
+             }
+             if (b_Underline)
+             {
+                    iDrop = yoff + m_iAscent + m_iDescent/3;
+                    if(!P_Run->isUnderline())
+                    {
+                          setUnderlineXoff( xoff);
+                          setMaxUnderline(iDrop);
+                    }
+                    else
+                    {
+                          setUnderlineXoff( P_Run->getUnderlineXoff());
+                           setMaxUnderline(UT_MAX( P_Run->getMaxUnderline(), iDrop));
+                    }
+               }
+             if (b_Overline)
+             {
+                    iDrop = yoff + (UT_MAX(10,m_iAscent) - 10)/8;
+                    if(!P_Run->isOverline())
+                    {
+                          setOverlineXoff( xoff);
+                          setMinOverline(iDrop);
+                    }
+                    else
+                    {
+                          setOverlineXoff( P_Run->getOverlineXoff());
+                           setMinOverline(UT_MIN( P_Run->getMinOverline(), iDrop));
+                    }
+               }
+       }
+       m_iLineWidth = getLinethickness();
        m_pG->setLineWidth(m_iLineWidth);
-       
-       if (m_fDecorations & TEXT_DECOR_UNDERLINE)
+       /*
+         If the next run returns NULL we've reached the of the line of text
+so the overlines and underlines must be drawn.
+       */
+       if(N_Run == NULL)
        {
-               UT_sint32 iDrop = (m_pLine->getDescent() / 3);
-               m_pG->drawLine(xoff, yoff + iDrop + m_iAscent, xoff+getWidth(), yoff + 
iDrop + m_iAscent);
+               if ( b_Underline)
+               {
+                    iDrop = UT_MAX( getMaxUnderline(), iDrop);
+                    UT_sint32 totx = getUnderlineXoff();
+                    m_pG->drawLine(totx, iDrop, xoff+getWidth(), iDrop);
+               }
+               if ( b_Overline)
+               {
+                    iDrop = UT_MIN( getMinOverline(), iDrop);
+                    UT_sint32 totx = getOverlineXoff();
+                    m_pG->drawLine(totx, iDrop, xoff+getWidth(), iDrop);
+               }
        }
-       if (m_fDecorations & TEXT_DECOR_OVERLINE)
+       /* 
+          Otherwise look to see if the next run has an underline or overline
+if not, draw the line, if does mark the next run as dirty to make sure it
+is drawn later.
+       */
+       else
        {
-               UT_sint32 y2 = yoff +  (UT_MAX(10,getAscent()) - 10)/8;
-               m_pG->drawLine(xoff, y2, xoff+getWidth(), y2);
+               if ( b_Underline )
+               {
+                    if(!N_Run->isUnderline())
+                    {
+                         iDrop = UT_MAX( getMaxUnderline(), iDrop);
+                         UT_sint32 totx = getUnderlineXoff();
+                         m_pG->drawLine(totx, iDrop, xoff+getWidth(), iDrop);
+                    }
+                    else
+                    {
+                         N_Run->markAsDirty();
+                    }
+               }
+               if ( b_Overline )
+               {
+                    if(!N_Run->isOverline())
+                    {
+                         iDrop = UT_MIN( getMinOverline(), iDrop);
+                         UT_sint32 totx = getOverlineXoff();
+                         m_pG->drawLine(totx, iDrop, xoff+getWidth(), iDrop);
+                    }
+                    else
+                    {
+                         N_Run->markAsDirty();
+                    }
+               }
        }
-
-       if (m_fDecorations & TEXT_DECOR_LINETHROUGH)
+       /*
+         We always want strikethrough to go right through the middle of the
+text so we can keep the original code.
+       */
+       if ( b_Strikethrough)
        {
-               UT_sint32 y2 = yoff + getAscent() * 2 / 3;
-               m_pG->drawLine(xoff, y2, xoff+getWidth(), y2);
+               iDrop = yoff + getAscent() * 2 / 3;
+               m_pG->drawLine(xoff, iDrop, xoff+getWidth(), iDrop);
        }
-
+       /* 
+          Restore the previous line width.
+       */ 
        m_iLineWidth = old_LineWidth;
        m_pG->setLineWidth(m_iLineWidth);
-
-
 }
 
 void fp_TextRun::_drawSquiggle(UT_sint32 top, UT_sint32 left, UT_sint32 right)
@@ -1034,7 +1163,7 @@
                // I think this is safe, although it begs the question, why did we get 
called if iLen is zero?  TODO
                return;
        }
-       
+
        UT_sint32 xoff = 0, yoff = 0;
        UT_sint32 iAscent = m_pLine->getAscent();
        UT_sint32 iDescent = m_pLine->getDescent();
@@ -1211,6 +1340,71 @@
 UT_Bool fp_TextRun::isSubscript(void) const
 {
        return (m_fPosition == TEXT_POSITION_SUBSCRIPT);
+}
+
+UT_Bool fp_TextRun::isUnderline(void) const
+{
+         return ((m_fDecorations & TEXT_DECOR_UNDERLINE) !=  0);
+}
+
+UT_Bool fp_TextRun::isOverline(void) const
+{
+         return ((m_fDecorations & TEXT_DECOR_OVERLINE) !=  0);
+}
+
+UT_Bool fp_TextRun::isStrikethrough(void) const
+{
+         return ((m_fDecorations & TEXT_DECOR_LINETHROUGH) !=  0);
+}
+
+void fp_TextRun::setLinethickness(UT_sint32 max_linethickness)
+{
+         m_iLinethickness = max_linethickness;
+}
+
+void fp_TextRun::setUnderlineXoff(UT_sint32 xoff)
+{
+         m_iUnderlineXoff = xoff;
+}
+
+UT_sint32 fp_TextRun::getUnderlineXoff(void)
+{
+         return m_iUnderlineXoff;
+}
+
+void fp_TextRun::setOverlineXoff(UT_sint32 xoff)
+{
+         m_iOverlineXoff = xoff;
+}
+
+UT_sint32 fp_TextRun::getOverlineXoff(void)
+{
+         return m_iOverlineXoff;
+}
+
+void fp_TextRun::setMaxUnderline(UT_sint32 maxh)
+{
+         m_imaxUnderline = maxh;
+}
+
+UT_sint32 fp_TextRun::getMaxUnderline(void)
+{
+         return m_imaxUnderline;
+}
+
+void fp_TextRun::setMinOverline(UT_sint32 minh)
+{
+         m_iminOverline = minh;
+}
+
+UT_sint32 fp_TextRun::getMinOverline(void)
+{
+         return m_iminOverline;
+}
+
+UT_sint32 fp_TextRun::getLinethickness( void)
+{
+         return m_iLinethickness;
 }
 
 UT_sint32 fp_TextRun::findTrailingSpaceDistance(void) const
diff -Naur --exclude=CVS --exclude=fv_View.h --exclude=fv_View.cpp 
--exclude=fl_BlockLayout.cpp --exclude=fp_Line.cpp abi/src/text/fmt/xp/fp_TextRun.h 
abi-new/src/text/fmt/xp/fp_TextRun.h
--- abi/src/text/fmt/xp/fp_TextRun.h    Sat Jan 29 12:07:13 2000
+++ abi-new/src/text/fmt/xp/fp_TextRun.h        Sat Mar 18 05:13:35 2000
@@ -76,6 +76,19 @@
        virtual UT_Bool                 doesContainNonBlankData(void) const;
        virtual UT_Bool                         isSuperscript(void) const;
        virtual UT_Bool                         isSubscript(void) const;
+       virtual UT_Bool                         isUnderline(void) const;
+       virtual UT_Bool                         isOverline(void) const;
+       virtual UT_Bool                         isStrikethrough(void) const;
+       virtual void                    setLinethickness(UT_sint32 max_linethickness);
+       virtual UT_sint32               getLinethickness(void);
+       virtual void                    setUnderlineXoff(UT_sint32 xoff);
+       virtual UT_sint32               getUnderlineXoff(void);
+       virtual void                    setOverlineXoff(UT_sint32 xoff);
+       virtual UT_sint32               getOverlineXoff(void);
+       virtual void                    setMaxUnderline(UT_sint32 xoff);
+       virtual UT_sint32               getMaxUnderline(void);
+       virtual void                    setMinOverline(UT_sint32 xoff);
+       virtual UT_sint32               getMinOverline(void);
        UT_uint32                               countTrailingSpaces(void) const;
 
 #ifdef FMT_TEST

Reply via email to