WebCore:
authorhyatt <hyatt@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 17 Jun 2004 01:38:30 +0000 (01:38 +0000)
committerhyatt <hyatt@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 17 Jun 2004 01:38:30 +0000 (01:38 +0000)
Fix for 3596620, implement a subset of CSS3 text truncation for Emerson.

        Reviewed by mjs

        * khtml/rendering/bidi.cpp:
        (khtml::RenderBlock::checkLinesForTextOverflow):
        * khtml/rendering/font.cpp:
        (Font::checkSelectionPoint):
        * khtml/rendering/font.h:
        * khtml/rendering/render_block.cpp:
        (khtml::RenderBlock::paintObject):
        (khtml::RenderBlock::paintFloats):
        (khtml::RenderBlock::paintEllipsisBoxes):
        * khtml/rendering/render_block.h:
        * khtml/rendering/render_line.cpp:
        (InlineBox::canAccommodateEllipsis):
        (InlineBox::placeEllipsisBox):
        (InlineFlowBox::paintDecorations):
        (InlineFlowBox::placeEllipsisBox):
        (EllipsisBox::paint):
        (RootInlineBox::placeEllipsis):
        (RootInlineBox::placeEllipsisBox):
        * khtml/rendering/render_line.h:
        (khtml::EllipsisBox::m_str):
        (khtml::RootInlineBox::ellipsisBox):
        * khtml/rendering/render_text.cpp:
        (InlineTextBox::placeEllipsisBox):
        (InlineTextBox::paintDecoration):
        (InlineTextBox::offsetForPosition):
        (RenderText::positionForCoordinates):
        (RenderText::paint):
        * khtml/rendering/render_text.h:
        * kwq/KWQFontMetrics.h:
        * kwq/KWQFontMetrics.mm:
        (QFontMetrics::checkSelectionPoint):
        * kwq/WebCoreTextRenderer.h:

WebKit:

In order to support truncation in Emerson, enhance pointToOffset so that it needn't include partial
character glyphs (the left half of a glyph).

        Reviewed by mjs

        * WebCoreSupport.subproj/WebTextRenderer.m:
        (-[WebTextRenderer pointToOffset:style:position:reversed:includePartialGlyphs:]):
        (-[WebTextRenderer _ATSU_pointToOffset:style:position:reversed:includePartialGlyphs:]):
        (-[WebTextRenderer _CG_pointToOffset:style:position:reversed:includePartialGlyphs:]):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@6873 268f45cc-cd09-0410-ab3c-d52691b4dbfc

15 files changed:
WebCore/ChangeLog-2005-08-23
WebCore/khtml/rendering/bidi.cpp
WebCore/khtml/rendering/font.cpp
WebCore/khtml/rendering/font.h
WebCore/khtml/rendering/render_block.cpp
WebCore/khtml/rendering/render_block.h
WebCore/khtml/rendering/render_line.cpp
WebCore/khtml/rendering/render_line.h
WebCore/khtml/rendering/render_text.cpp
WebCore/khtml/rendering/render_text.h
WebCore/kwq/KWQFontMetrics.h
WebCore/kwq/KWQFontMetrics.mm
WebCore/kwq/WebCoreTextRenderer.h
WebKit/ChangeLog
WebKit/WebCoreSupport.subproj/WebTextRenderer.m

index de01419..7a9bb7b 100644 (file)
@@ -1,3 +1,42 @@
+2004-06-16  David Hyatt  <hyatt@apple.com>
+
+       Fix for 3596620, implement a subset of CSS3 text truncation for Emerson.
+       
+        Reviewed by mjs
+
+        * khtml/rendering/bidi.cpp:
+        (khtml::RenderBlock::checkLinesForTextOverflow):
+        * khtml/rendering/font.cpp:
+        (Font::checkSelectionPoint):
+        * khtml/rendering/font.h:
+        * khtml/rendering/render_block.cpp:
+        (khtml::RenderBlock::paintObject):
+        (khtml::RenderBlock::paintFloats):
+        (khtml::RenderBlock::paintEllipsisBoxes):
+        * khtml/rendering/render_block.h:
+        * khtml/rendering/render_line.cpp:
+        (InlineBox::canAccommodateEllipsis):
+        (InlineBox::placeEllipsisBox):
+        (InlineFlowBox::paintDecorations):
+        (InlineFlowBox::placeEllipsisBox):
+        (EllipsisBox::paint):
+        (RootInlineBox::placeEllipsis):
+        (RootInlineBox::placeEllipsisBox):
+        * khtml/rendering/render_line.h:
+        (khtml::EllipsisBox::m_str):
+        (khtml::RootInlineBox::ellipsisBox):
+        * khtml/rendering/render_text.cpp:
+        (InlineTextBox::placeEllipsisBox):
+        (InlineTextBox::paintDecoration):
+        (InlineTextBox::offsetForPosition):
+        (RenderText::positionForCoordinates):
+        (RenderText::paint):
+        * khtml/rendering/render_text.h:
+        * kwq/KWQFontMetrics.h:
+        * kwq/KWQFontMetrics.mm:
+        (QFontMetrics::checkSelectionPoint):
+        * kwq/WebCoreTextRenderer.h:
+
 2004-06-16  Maciej Stachowiak  <mjs@apple.com>
 
         Reviewed by John.
index 008cc51..3285d27 100644 (file)
@@ -2277,15 +2277,15 @@ void RenderBlock::checkLinesForTextOverflow()
                     borderLeft() + paddingLeft(); // FIXME: In theory we will one day do RTL scrollbars, and then this
                                                   // RTL computation will want to add in the vertical scroller's width.
     for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
-        int lineBoxEdge = ltr ? curr->xPos() : curr->xPos() + curr->width();
+        int lineBoxEdge = ltr ? curr->xPos() + curr->width() : curr->xPos();
         if ((ltr && lineBoxEdge > blockEdge) || (!ltr && lineBoxEdge < blockEdge)) {
             // This line spills out of our box in the appropriate direction.  Now we need to see if the line
             // can be truncated.  In order for truncation to be possible, the line must have sufficient space to
             // accommodate our truncation string, and no replaced elements (images, tables) can overlap the ellipsis
             // space.
             int width = curr == firstRootBox() ? firstLineEllipsisWidth : ellipsisWidth;
-            if (curr->canAccommodateEllipsis(ltr, lineBoxEdge, blockEdge, width))
-                curr->placeEllipsis(ellipsisStr, blockEdge, ltr, width);
+            if (curr->canAccommodateEllipsis(ltr, blockEdge, lineBoxEdge, width))
+                curr->placeEllipsis(ellipsisStr, ltr, blockEdge, width);
         }
     }
 }
index 24367b0..35b544b 100644 (file)
@@ -126,9 +126,9 @@ void Font::floatCharacterWidths( QChar *str, int slen, int pos, int len, int toA
     fm.floatCharacterWidths(str, slen, pos, len, toAdd, buffer, letterSpacing, wordSpacing, fontDef.smallCaps);
 }
 
-int Font::checkSelectionPoint (QChar *s, int slen, int pos, int len, int toAdd, int x, bool reversed) const
+int Font::checkSelectionPoint (QChar *s, int slen, int pos, int len, int toAdd, int x, bool reversed, bool includePartialGlyphs) const
 {
-    return fm.checkSelectionPoint (s, slen, pos, len, toAdd, letterSpacing, wordSpacing, fontDef.smallCaps, x, reversed);
+    return fm.checkSelectionPoint (s, slen, pos, len, toAdd, letterSpacing, wordSpacing, fontDef.smallCaps, x, reversed, includePartialGlyphs);
 }
 
 #endif
index 2d1220b..8f7783c 100644 (file)
@@ -129,7 +129,7 @@ public:
     float floatWidth( QChar *str, int slen, int pos, int len ) const;
     void floatCharacterWidths( QChar *str, int slen, int pos, int len, int toAdd, float *buffer) const;
     bool isFixedPitch() const;
-    int checkSelectionPoint (QChar *s, int slen, int pos, int len, int toAdd, int x, bool reversed) const;
+    int checkSelectionPoint (QChar *s, int slen, int pos, int len, int toAdd, int x, bool reversed, bool includePartialGlyphs) const;
     void drawHighlightForText( QPainter *p, int x, int minX, int maxX, int y, int h, 
                    QChar *str, int slen, int pos, int len, int width,
                    QPainter::TextDirection d, bool visuallyOrdered = false, int from=-1, int to=-1, QColor bg=QColor()) const;
index 4e9b504..629c504 100644 (file)
@@ -1289,7 +1289,8 @@ void RenderBlock::paintObject(PaintInfo& i, int _tx, int _ty)
         }
     }
     paintLineBoxDecorations(paintInfo, scrolledX, scrolledY, true); // Strike-through
-    
+    paintEllipsisBoxes(paintInfo, scrolledX, scrolledY);
+
     // 3. paint floats.
     if (!inlineFlow && (paintAction == PaintActionFloat || paintAction == PaintActionSelection))
         paintFloats(paintInfo, scrolledX, scrolledY, paintAction == PaintActionSelection);
@@ -1356,6 +1357,31 @@ void RenderBlock::paintFloats(PaintInfo& i, int _tx, int _ty, bool paintSelectio
     }
 }
 
+void RenderBlock::paintEllipsisBoxes(PaintInfo& i, int _tx, int _ty)
+{
+    if (!shouldPaintWithinRoot(i) || !firstLineBox())
+        return;
+
+    if (style()->visibility() == VISIBLE && i.phase == PaintActionForeground) {
+        // We can check the first box and last box and avoid painting if we don't
+        // intersect.
+        int yPos = _ty + firstLineBox()->yPos();;
+        int h = lastLineBox()->yPos() + lastLineBox()->height() - firstLineBox()->yPos();
+        if( (yPos >= i.r.y() + i.r.height()) || (yPos + h <= i.r.y()))
+            return;
+
+        // See if our boxes intersect with the dirty rect.  If so, then we paint
+        // them.  Note that boxes can easily overlap, so we can't make any assumptions
+        // based off positions of our first line box or our last line box.
+        for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
+            yPos = _ty + curr->yPos();
+            h = curr->height();
+            if (curr->ellipsisBox() && (yPos < i.r.y() + i.r.height()) && (yPos + h > i.r.y()))
+                curr->ellipsisBox()->paint(i, _tx, _ty);
+        }
+    }
+}
+
 void RenderBlock::insertPositionedObject(RenderObject *o)
 {
     // Create the list of special objects if we don't aleady have one
index 64c1e6b..82cb783 100644 (file)
@@ -133,6 +133,7 @@ public:
     virtual void paint(PaintInfo& i, int tx, int ty);
     void paintObject(PaintInfo& i, int tx, int ty);
     void paintFloats(PaintInfo& i, int _tx, int _ty, bool paintSelection = false);
+    void paintEllipsisBoxes(PaintInfo& i, int _tx, int _ty);
 
     void insertFloatingObject(RenderObject *o);
     void removeFloatingObject(RenderObject *o);
index 0e4ec09..99d72f4 100644 (file)
@@ -187,11 +187,17 @@ bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidt
     if (!m_object || !m_object->isReplaced())
         return true;
     
-    QRect boxRect(m_x, 0, m_width, 1);
-    QRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 1);
+    QRect boxRect(m_x, 0, m_width, 10);
+    QRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
     return !(boxRect.intersects(ellipsisRect));
 }
 
+int InlineBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool&)
+{
+    // Use -1 to mean "we didn't set the position."
+    return -1;
+}
+
 int InlineFlowBox::marginLeft()
 {
     if (!includeLeftEdge())
@@ -720,6 +726,26 @@ void InlineFlowBox::paintDecorations(RenderObject::PaintInfo& i, int _tx, int _t
     if (deco != TDNONE && 
         ((!paintedChildren && ((deco & UNDERLINE) || (deco & OVERLINE))) || (paintedChildren && (deco & LINE_THROUGH))) &&
         shouldDrawDecoration(object())) {
+        int x = m_x + borderLeft() + paddingLeft();
+        int w = m_width - (borderLeft() + paddingLeft() + borderRight() + paddingRight());
+        RootInlineBox* rootLine = root();
+        if (rootLine->ellipsisBox()) {
+            int ellipsisX = rootLine->ellipsisBox()->xPos();
+            int ellipsisWidth = rootLine->ellipsisBox()->width();
+            
+            // FIXME: Will need to work with RTL
+            if (rootLine == this) {
+                if (x + w >= ellipsisX + ellipsisWidth)
+                    w -= (x + w - ellipsisX - ellipsisWidth);
+            }
+            else {
+                if (x >= ellipsisX)
+                    return;
+                if (x + w >= ellipsisX)
+                    w -= (x + w - ellipsisX);
+            }
+        }
+            
 #if APPLE_CHANGES
         // Set up the appropriate text-shadow effect for the decoration.
         // FIXME: Support multiple shadow effects.  Need more from the CG API before we can do this.
@@ -733,7 +759,7 @@ void InlineFlowBox::paintDecorations(RenderObject::PaintInfo& i, int _tx, int _t
         
         // We must have child boxes and have decorations defined.
         _tx += borderLeft() + paddingLeft();
-        int w = m_width - (borderLeft() + paddingLeft() + borderRight() + paddingRight());
+        
         QColor underline, overline, linethrough;
         underline = overline = linethrough = styleToUse->color();
         if (!parent())
@@ -820,6 +846,47 @@ bool InlineFlowBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsis
     return true;
 }
 
+int InlineFlowBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox)
+{
+    int result = -1;
+    for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) {
+        int currResult = box->placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox);
+        if (currResult != -1 && result == -1)
+            result = currResult;
+    }
+    return result;
+}
+
+void EllipsisBox::paint(const RenderObject::PaintInfo& i, int _tx, int _ty)
+{
+    QPainter* p = i.p;
+    RenderStyle* _style = m_firstLine ? m_object->style(true) : m_object->style();
+    if (_style->font() != p->font())
+        p->setFont(_style->font());
+
+    const Font* font = &_style->htmlFont();
+    QColor textColor = _style->color();
+    if (textColor != p->pen().color())
+        p->setPen(textColor);
+    bool setShadow = false;
+    if (_style->textShadow()) {
+        p->setShadow(_style->textShadow()->x, _style->textShadow()->y,
+                     _style->textShadow()->blur, _style->textShadow()->color);
+        setShadow = true;
+    }
+    
+    const DOMString& str = m_str.string();
+    font->drawText(p, m_x + _tx, 
+                      m_y + _ty + m_baseline,
+                      (str.implementation())->s,
+                      str.length(), 0, str.length(),
+                      0, 
+                      QPainter::LTR, _style->visuallyOrdered());
+                      
+    if (setShadow)
+        p->clearShadow();
+}
+
 void RootInlineBox::detach(RenderArena* arena)
 {
     detachEllipsisBox(arena);
@@ -846,15 +913,25 @@ bool RootInlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxE
     return InlineFlowBox::canAccommodateEllipsis(ltr, blockEdge, ellipsisWidth);
 }
 
-void RootInlineBox::placeEllipsis(const AtomicString& ellipsisStr, int blockEdge, bool ltr, int ellipsisWidth)
+void RootInlineBox::placeEllipsis(const AtomicString& ellipsisStr,  bool ltr, int blockEdge, int ellipsisWidth)
 {
     // Create an ellipsis box.
     m_ellipsisBox = new (m_object->renderArena()) EllipsisBox(m_object, ellipsisStr, this, ellipsisWidth,
-                                                              yPos(), height(), baseline());
+                                                              yPos(), height(), baseline(), !prevRootBox());
 
     // Now attempt to find the nearest glyph horizontally and place just to the right (or left in RTL)
     // of that glyph.  Mark all of the objects that intersect the ellipsis box as not painting (as being
     // truncated).
+    bool foundBox = false;
+    m_ellipsisBox->m_x = placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox);
+}
+
+int RootInlineBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox)
+{
+    int result = InlineFlowBox::placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox);
+    if (result == -1)
+        result = ltr ? blockEdge - ellipsisWidth : blockEdge;
+    return result;
 }
 
 void RootInlineBox::adjustVerticalPosition(int delta)
index d9ce605..4336ed1 100644 (file)
@@ -32,7 +32,7 @@ namespace khtml {
 
 class InlineFlowBox;
 class RootInlineBox;
-    
+
 // InlineBox represents a rectangle that occurs on a line.  It corresponds to
 // some RenderObject (i.e., it represents a portion of that RenderObject).
 class InlineBox
@@ -135,7 +135,8 @@ public:
     void dirtyLineBoxes();
     
     virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth);
-    
+    virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool&);
+
 public: // FIXME: Would like to make this protected, but methods are accessing these
         // members over in the part.
     RenderObject* m_object;
@@ -267,7 +268,8 @@ public:
     void removeChild(InlineBox* child);
     
     virtual bool canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth);
-    
+    virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool&);
+
 protected:
     InlineBox* m_firstChild;
     InlineBox* m_lastChild;
@@ -280,15 +282,19 @@ class EllipsisBox : public InlineBox
 {
 public:
     EllipsisBox(RenderObject* obj, const DOM::AtomicString& ellipsisStr, InlineFlowBox* p,
-                int w, int y, int h, int b)
+                int w, int y, int h, int b, bool firstLine)
     :InlineBox(obj), m_str(ellipsisStr) {
         m_parent = p;
         m_width = w;
         m_y = y;
         m_height = h;
         m_baseline = b;
+        m_firstLine = firstLine;
+        m_constructed = true;
     }
 
+    void paint(const RenderObject::PaintInfo& i, int _tx, int _ty);
+    
 private:
     DOM::AtomicString m_str;
 };
@@ -329,8 +335,11 @@ public:
     void childRemoved(InlineBox* box);
 
     bool canAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxEdge, int ellipsisWidth);
-    void placeEllipsis(const DOM::AtomicString& ellipsisStr, int blockEdge, bool ltr, int ellipsisWidth);
+    void placeEllipsis(const DOM::AtomicString& ellipsisStr, bool ltr, int blockEdge, int ellipsisWidth);
+    virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool&);
 
+    EllipsisBox* ellipsisBox() const { return m_ellipsisBox; }
+        
 protected:
     // Normally we are only as tall as the style on our block dictates, but we might have content
     // that spills out above the height of our font (e.g, a tall image), or something that extends further
index c77b682..d600004 100644 (file)
@@ -94,6 +94,49 @@ void InlineTextBox::attachLine()
     static_cast<RenderText*>(m_object)->attachTextBox(this);
 }
 
+int InlineTextBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox)
+{
+    if (foundBox) {
+        m_truncation = cFullTruncation;
+        return -1;
+    }
+
+    int ellipsisX = ltr ? blockEdge - ellipsisWidth : blockEdge + ellipsisWidth;
+    
+    // For LTR, if the left edge of the ellipsis is to the left of our text run, then we are the run that will get truncated.
+    if (ltr) {
+        if (ellipsisX <= m_x) {
+            // Too far.  Just set full truncation, but return -1 and let the ellipsis just be placed at the edge of the box.
+            m_truncation = cFullTruncation;
+            foundBox = true;
+            return -1;
+        }
+
+        if (ellipsisX < m_x + m_width) {
+            if (m_reversed)
+                return -1; // FIXME: Support LTR truncation when the last run is RTL someday.
+
+            foundBox = true;
+
+            int offset = offsetForPosition(ellipsisX, false);
+            if (offset == 0) {
+                // No characters should be rendered.  Set ourselves to full truncation and place the ellipsis at the min of our start
+                // and the ellipsis edge.
+                m_truncation = cFullTruncation;
+                return kMin(ellipsisX, m_x);
+            }
+            
+            // Set the truncation index on the text run.  The ellipsis needs to be placed just after the last visible character.
+            m_truncation = offset + m_start;
+            return m_x + static_cast<RenderText*>(m_object)->width(m_start, offset, m_firstLine);
+        }
+    }
+    else {
+        // FIXME: Support RTL truncation someday, including both modes (when the leftmost run on the line is either RTL or LTR)
+    }
+    return -1;
+}
+
 void InlineTextBox::paintSelection(const Font *f, RenderText *text, QPainter *p, RenderStyle* style, int tx, int ty, int startPos, int endPos, bool extendSelection)
 {
     int offset = m_start;
@@ -164,6 +207,12 @@ void InlineTextBox::paintDecoration( QPainter *pt, int _tx, int _ty, int deco)
     _tx += m_x;
     _ty += m_y;
 
+    if (m_truncation == cFullTruncation)
+        return;
+    
+    int width = (m_truncation == cNoTruncation) ? 
+                m_width : static_cast<RenderText*>(m_object)->width(m_start, m_truncation - m_start, m_firstLine);
+    
     // Get the text decoration colors.
     QColor underline, overline, linethrough;
     object()->getTextDecorationColors(deco, underline, overline, linethrough, true);
@@ -171,15 +220,15 @@ void InlineTextBox::paintDecoration( QPainter *pt, int _tx, int _ty, int deco)
     // Use a special function for underlines to get the positioning exactly right.
     if (deco & UNDERLINE) {
         pt->setPen(underline);
-        pt->drawLineForText(_tx, _ty, m_baseline, m_width);
+        pt->drawLineForText(_tx, _ty, m_baseline, width);
     }
     if (deco & OVERLINE) {
         pt->setPen(overline);
-        pt->drawLineForText(_tx, _ty, 0, m_width);
+        pt->drawLineForText(_tx, _ty, 0, width);
     }
     if (deco & LINE_THROUGH) {
         pt->setPen(linethrough);
-        pt->drawLineForText(_tx, _ty, 2*m_baseline/3, m_width);
+        pt->drawLineForText(_tx, _ty, 2*m_baseline/3, width);
     }
 }
 #else
@@ -230,38 +279,11 @@ unsigned long InlineTextBox::caretMaxRenderedOffset() const
 
 #define LOCAL_WIDTH_BUF_SIZE   1024
 
-int InlineTextBox::offsetForPosition(int _x, int _tx, const Font *f, const RenderText *text)
+int InlineTextBox::offsetForPosition(int _x, bool includePartialGlyphs)
 {
-#if APPLE_CHANGES
-    return f->checkSelectionPoint(text->str->s, text->str->l, m_start, m_len, m_toAdd, _x - (_tx + m_x), m_reversed);
-#else
-    int pos = 0;
-    int delta = _x - (_tx + m_x);
-    if (m_reversed) {
-        delta -= m_width;
-        while (pos < m_len) {
-            int w = f->width( text->str->s, text->str->l, m_start + pos);
-            int w2 = w/2;
-            w -= w2;
-            delta += w2;
-            if(delta >= 0) break;
-            pos++;
-            delta += w;
-        }
-    } 
-    else {
-        while (pos < m_len) {
-            int w = f->width( text->str->s, text->str->l, m_start + pos);
-            int w2 = w/2;
-            w -= w2;
-            delta -= w2;
-            if(delta <= 0) break;
-            pos++;
-            delta -= w;
-        }
-    }
-    return pos;
-#endif
+    RenderText* text = static_cast<RenderText*>(m_object);
+    const Font* f = text->htmlFont(m_firstLine);
+    return f->checkSelectionPoint(text->str->s, text->str->l, m_start, m_len, m_toAdd, _x - m_x, m_reversed, includePartialGlyphs);
 }
 
 // -------------------------------------------------------------------------------------
@@ -491,8 +513,7 @@ Position RenderText::positionForCoordinates(int _x, int _y)
             if (_x < absx + box->m_x + box->m_width) {
                 // and the x coordinate is to the left of the right edge of this box
                 // check to see if position goes in this box
-                const Font *f = htmlFont(box == firstTextBox());
-                int offset = box->offsetForPosition(_x, absx, f, this);
+                int offset = box->offsetForPosition(_x - absx);
                 if (offset != -1) {
                     return Position(element(), offset + box->m_start);
                 }
@@ -677,6 +698,9 @@ void RenderText::paint(PaintInfo& i, int tx, int ty)
             }
         }
 
+        if (s->m_truncation == cFullTruncation)
+            continue;
+        
         RenderStyle* _style = pseudoStyle && s->m_firstLine ? pseudoStyle : style();
 
         if (_style->font() != p->font())
@@ -729,15 +753,14 @@ void RenderText::paint(PaintInfo& i, int tx, int ty)
             }
             
             if (!paintSelectedTextOnly && !paintSelectedTextSeparately) {
-#if APPLE_CHANGES
+                // FIXME: Handle RTL direction, handle reversed strings.  For now truncation can only be turned on
+                // for non-reversed LTR strings.
+                int endPoint = s->m_len;
+                if (s->m_truncation != cNoTruncation)
+                    endPoint = s->m_truncation - s->m_start;
                 font->drawText(p, s->m_x + tx, s->m_y + ty + s->m_baseline,
-                               str->s, str->l, s->m_start, s->m_len,
+                               str->s, str->l, s->m_start, endPoint,
                                s->m_toAdd, s->m_reversed ? QPainter::RTL : QPainter::LTR, style()->visuallyOrdered());
-#else
-                font->drawText(p, s->m_x + tx, s->m_y + ty + s->m_baseline,
-                               str->s, str->l, s->m_start, s->m_len,
-                               s->m_toAdd, s->m_reversed ? QPainter::RTL : QPainter::LTR);
-#endif
             }
             else {
                 int offset = s->m_start;
index 112dd44..9d4ec38 100644 (file)
@@ -80,6 +80,7 @@ public:
     virtual void attachLine();
 
     void clearTruncation() { m_truncation = cNoTruncation; }
+    virtual int placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool& foundBox);
 
     // Overloaded new operator.  Derived classes must override operator new
     // in order to allocate out of the RenderArena.
@@ -105,7 +106,7 @@ public:
     virtual long caretMaxOffset() const;
     virtual unsigned long caretMaxRenderedOffset() const;
     
-    int offsetForPosition(int _x, int _tx, const Font *f, const RenderText *text);
+    int offsetForPosition(int _x, bool includePartialGlyphs = true);
     
     /**
      * if this text run was rendered @ref _ty pixels below the upper edge
index ff1ef46..29477eb 100644 (file)
@@ -60,7 +60,7 @@ public:
                      int letterSpacing, int wordSpacing, bool smallCaps) const;
     float floatCharacterWidths(const QChar *, int slen, int pos, int len, int toAdd, float *buffer,
                                int letterSpacing, int wordSpacing, bool smallCaps) const;
-    int checkSelectionPoint (QChar *s, int slen, int pos, int len, int toAdd, int letterSpacing, int wordSpacing, bool smallCaps, int x, bool reversed) const;
+    int checkSelectionPoint (QChar *s, int slen, int pos, int len, int toAdd, int letterSpacing, int wordSpacing, bool smallCaps, int x, bool reversed, bool includePartialGlyphs) const;
 
     QRect boundingRect(const QString &, int len=-1) const;
     QRect boundingRect(int, int, int, int, int, const QString &) const;
index 50d0dea..aec99d6 100644 (file)
@@ -291,7 +291,7 @@ float QFontMetrics::floatCharacterWidths(const QChar *uchars, int slen, int pos,
     return [data->getRenderer() floatWidthForRun:&run style:&style widths:buffer];
 }
 
-int QFontMetrics::checkSelectionPoint (QChar *s, int slen, int pos, int len, int toAdd, int letterSpacing, int wordSpacing, bool smallCaps, int x, bool reversed) const
+int QFontMetrics::checkSelectionPoint (QChar *s, int slen, int pos, int len, int toAdd, int letterSpacing, int wordSpacing, bool smallCaps, int x, bool reversed, bool includePartialGlyphs) const
 {
     if (data.isNull()) {
         ERROR("called floatWidth on an empty QFontMetrics");
@@ -311,7 +311,7 @@ int QFontMetrics::checkSelectionPoint (QChar *s, int slen, int pos, int len, int
     style.families = families;
     style.padding = toAdd;
 
-    return [data->getRenderer() pointToOffset:&run style:&style position:x reversed:reversed];
+    return [data->getRenderer() pointToOffset:&run style:&style position:x reversed:reversed includePartialGlyphs:includePartialGlyphs];
 }
 
 QRect QFontMetrics::boundingRect(const QString &qstring, int len) const
index bf39608..b6deaee 100644 (file)
@@ -102,5 +102,5 @@ extern void WebCoreInitializeEmptyTextGeometry(WebCoreTextGeometry *geometry);
 - (void)drawLineForCharacters:(NSPoint)point yOffset:(float)yOffset withWidth:(int)width withColor:(NSColor *)color;
 
 // selection point check
-- (int)pointToOffset:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style position:(int)x reversed:(BOOL)reversed;
+- (int)pointToOffset:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style position:(int)x reversed:(BOOL)reversed includePartialGlyphs:(BOOL)includePartialGlyphs;
 @end
index 5f2d485..3da5ff7 100644 (file)
@@ -1,3 +1,15 @@
+2004-06-16  David Hyatt  <hyatt@apple.com>
+
+       In order to support truncation in Emerson, enhance pointToOffset so that it needn't include partial
+       character glyphs (the left half of a glyph).
+       
+        Reviewed by mjs
+
+        * WebCoreSupport.subproj/WebTextRenderer.m:
+        (-[WebTextRenderer pointToOffset:style:position:reversed:includePartialGlyphs:]):
+        (-[WebTextRenderer _ATSU_pointToOffset:style:position:reversed:includePartialGlyphs:]):
+        (-[WebTextRenderer _CG_pointToOffset:style:position:reversed:includePartialGlyphs:]):
+
 === Safari-145 ===
 
 2004-06-16  Darin Adler  <darin@apple.com>
index 264c911..48e2faa 100644 (file)
@@ -145,8 +145,8 @@ struct CharacterWidthIterator
 - (void)_ATSU_drawRun:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style geometry:(const WebCoreTextGeometry *)geometry;
 
 // Selection point detection in runs.
-- (int)_CG_pointToOffset:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style position:(int)x reversed:(BOOL)reversed;
-- (int)_ATSU_pointToOffset:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style position:(int)x reversed:(BOOL)reversed;
+- (int)_CG_pointToOffset:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style position:(int)x reversed:(BOOL)reversed includePartialGlyphs:(BOOL)includePartialGlyphs;
+- (int)_ATSU_pointToOffset:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style position:(int)x reversed:(BOOL)reversed includePartialGlyphs:(BOOL)includePartialGlyphs;
 
 // Drawing highlight for runs.
 - (void)_CG_drawHighlightForRun:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style geometry:(const WebCoreTextGeometry *)geometry;
@@ -518,15 +518,15 @@ static BOOL alwaysUseATSU = NO;
     }
 }
 
-- (int)pointToOffset:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style position:(int)x reversed:(BOOL)reversed
+- (int)pointToOffset:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style position:(int)x reversed:(BOOL)reversed includePartialGlyphs:(BOOL)includePartialGlyphs
 {
     if (style->smallCaps && !isSmallCapsRenderer) {
-        return [[self _smallCapsRenderer] pointToOffset:run style:style position:x reversed:reversed];
+        return [[self _smallCapsRenderer] pointToOffset:run style:style position:x reversed:reversed includePartialGlyphs:includePartialGlyphs];
     }
 
     if (shouldUseATSU(run))
-        return [self _ATSU_pointToOffset:run style:style position:x reversed:reversed];
-    return [self _CG_pointToOffset:run style:style position:x reversed:reversed];
+        return [self _ATSU_pointToOffset:run style:style position:x reversed:reversed includePartialGlyphs:includePartialGlyphs];
+    return [self _CG_pointToOffset:run style:style position:x reversed:reversed includePartialGlyphs:includePartialGlyphs];
 }
 
 @end
@@ -1548,7 +1548,7 @@ static WebCoreTextRun reverseCharactersInRun(const WebCoreTextRun *run)
         free ((void *)swappedRun.characters);
 }
 
-- (int)_ATSU_pointToOffset:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style position:(int)x reversed:(BOOL)reversed
+- (int)_ATSU_pointToOffset:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style position:(int)x reversed:(BOOL)reversed includePartialGlyphs:(BOOL)includePartialGlyphs
 {
     // The only Cocoa calls made here is to the self call to
     // _createATSUTextLayoutForRun:. This is exception-safe.
@@ -1571,6 +1571,9 @@ static WebCoreTextRun reverseCharactersInRun(const WebCoreTextRun *run)
     layout = [self _createATSUTextLayoutForRun:aRun];
 
     primaryOffset = aRun->from;
+    
+    // FIXME: No idea how to avoid including partial glyphs.   Not even sure if that's the behavior
+    // this yields now.
     status = ATSUPositionToOffset(layout, FloatToFixed(x), FloatToFixed(-1), &primaryOffset, &isLeading, &secondaryOffset);
     if (status == noErr){
         offset = (unsigned)primaryOffset;
@@ -1586,7 +1589,7 @@ static WebCoreTextRun reverseCharactersInRun(const WebCoreTextRun *run)
     return offset - aRun->from;
 }
 
-- (int)_CG_pointToOffset:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style position:(int)x reversed:(BOOL)reversed
+- (int)_CG_pointToOffset:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style position:(int)x reversed:(BOOL)reversed includePartialGlyphs:(BOOL)includePartialGlyphs
 {
     float delta = (float)x;
     float width;
@@ -1600,37 +1603,39 @@ static WebCoreTextRun reverseCharactersInRun(const WebCoreTextRun *run)
         delta -= width;
         while (offset < run->length) {
             float w = widthForNextCharacter(&widthIterator, 0, 0);
-            if (w == INVALID_WIDTH){
+            if (w == INVALID_WIDTH) {
                 // Something very bad happened, like we only have half of a surrogate pair.
                 break;
             }
             else {
-                if (w){
-                    float w2 = w/2;
-                    w -= w2;
-                    delta += w2;
+                if (w) {
+                    if (includePartialGlyphs)
+                       w -= w/2;
+                    delta += w;
                     if(delta >= 0)
                         break;
-                    delta += w;
+                    if (includePartialGlyphs)
+                        delta += w;
                 }
                 offset = widthIterator.currentCharacter;
             }
         }
     } else {
-        while(offset < run->length) {
+        while (offset < run->length) {
             float w = widthForNextCharacter(&widthIterator, 0, 0);
-            if (w == INVALID_WIDTH){
+            if (w == INVALID_WIDTH) {
                 // Something very bad happened, like we only have half of a surrogate pair.
                 break;
             }
             else {
-                if (w){
-                    float w2 = w/2;
-                    w -= w2;
-                    delta -= w2;
+                if (w) {
+                    if (includePartialGlyphs)
+                        w -= w/2;
+                    delta -= w;
                     if(delta <= 0) 
                         break;
-                    delta -= w;
+                    if (includePartialGlyphs)
+                        delta -= w;
                 }
                 offset = widthIterator.currentCharacter;
             }