Reviewed by Darin, landed by ap.
authorap <ap@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 30 Dec 2005 22:17:09 +0000 (22:17 +0000)
committerap <ap@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 30 Dec 2005 22:17:09 +0000 (22:17 +0000)
        - fix for http://bugzilla.opendarwin.org/show_bug.cgi?id=5461
          Text width measured incorrectly when text-align: justify

WebCore:
        * khtml/rendering/font.h:
        * khtml/rendering/font.cpp:
        (khtml::Font::selectionRectForText): Added.
        * khtml/rendering/render_text.cpp:
        (kthml::InlineTextBox::selectionRect): Use selectionRectForText. This
        works for justified text as well, and avoids intermediate rounding which
        resulted in selection rects narrower than AppKit's.
        (khtml::InlineTextBox::positionForOffset): Use selectionRectForText,
        which works for justified text as well.
        * kwq/KWQFontMetrics.h:
        * kwq/KWQFontMetrics.mm:
        (QFontMetrics::selectionRectForText): Added.
        * kwq/WebCoreTextRenderer.h:

WebKit:
        * WebCoreSupport.subproj/WebTextRenderer.m:
        (-[WebTextRenderer selectionRectForRun:style:geometry:]): Added.
        (CG_drawHighlight): Use new function CG_selectionRect.
        (CG_selectionRect): New function to compute the selection rect.
        Eliminated rounding hackery that was required for keeping the highlight
        rect within the selection rect computed by
        InlineTextBox::selectionRect, since the latter uses this function now.
        The new selection rect is wider and matches AppKit more closely,
        although the right hand side is roundf()ed instead of cielf()ed for
        optimal caret positioning.
        (ATSU_drawHighlight): Use new function ATSU_selectionRect.
        (ATSU_selectionRect): New function to compute the selection rect.
        Much like CG_selectionRect.
LayoutTests:
        * fast/text/justified-text-rect-expected.checksum: Added.
        * fast/text/justified-text-rect-expected.png: Added.
        * fast/text/justified-text-rect-expected.txt: Added.
        * fast/text/justified-text-rect.html: Added.

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

14 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/text/justified-text-rect-expected.checksum [new file with mode: 0644]
LayoutTests/fast/text/justified-text-rect-expected.png [new file with mode: 0644]
LayoutTests/fast/text/justified-text-rect-expected.txt [new file with mode: 0644]
LayoutTests/fast/text/justified-text-rect.html [new file with mode: 0644]
WebCore/ChangeLog
WebCore/khtml/rendering/font.cpp
WebCore/khtml/rendering/font.h
WebCore/khtml/rendering/render_text.cpp
WebCore/kwq/KWQFontMetrics.h
WebCore/kwq/KWQFontMetrics.mm
WebCore/kwq/WebCoreTextRenderer.h
WebKit/ChangeLog
WebKit/WebCoreSupport.subproj/WebTextRenderer.m

index 4b83ad5acfd013c77a2b9bea3f3923ab4efb3ead..1a286e7f749f6cdf19f0eb9a03a3353f36c8f9ae 100644 (file)
@@ -1,3 +1,15 @@
+2005-12-30  Alexey Proskuryakov  <ap@nypop.com>
+
+        Reviewed by Darin.
+        
+        - test for http://bugzilla.opendarwin.org/show_bug.cgi?id=5461
+          Text width measured incorrectly when text-align: justify
+        
+        * fast/text/justified-text-rect-expected.checksum: Added.
+        * fast/text/justified-text-rect-expected.png: Added.
+        * fast/text/justified-text-rect-expected.txt: Added.
+        * fast/text/justified-text-rect.html: Added.
+
 2005-12-30  Eric Seidel  <eseidel@apple.com>
 
         Reviewed by ggaren.
diff --git a/LayoutTests/fast/text/justified-text-rect-expected.checksum b/LayoutTests/fast/text/justified-text-rect-expected.checksum
new file mode 100644 (file)
index 0000000..2fe6868
--- /dev/null
@@ -0,0 +1,2 @@
+f711e51f2e376d82b547ae37e94e263b
+\ No newline at end of file
diff --git a/LayoutTests/fast/text/justified-text-rect-expected.png b/LayoutTests/fast/text/justified-text-rect-expected.png
new file mode 100644 (file)
index 0000000..4d4a617
Binary files /dev/null and b/LayoutTests/fast/text/justified-text-rect-expected.png differ
diff --git a/LayoutTests/fast/text/justified-text-rect-expected.txt b/LayoutTests/fast/text/justified-text-rect-expected.txt
new file mode 100644 (file)
index 0000000..310a3d6
--- /dev/null
@@ -0,0 +1,17 @@
+EDITING DELEGATE: webViewDidChangeSelection:WebViewDidChangeSelectionNotification
+layer at (0,0) size 800x600
+  RenderCanvas at (0,0) size 800x600
+layer at (0,0) size 800x600
+  RenderBlock {HTML} at (0,0) size 800x600
+    RenderBody {BODY} at (0,0) size 800x584
+      RenderBlock {P} at (0,0) size 70x50 [bgcolor=#008000]
+        RenderText {TEXT} at (0,0) size 70x36
+          text run at (0,0) width 70: "a         a"
+          text run at (0,18) width 39: "        a"
+      RenderBlock (anonymous) at (0,66) size 800x18
+        RenderText {TEXT} at (0,0) size 76x18
+          text run at (0,0) width 76: "63,582,6,18"
+      RenderBlock {P} at (0,100) size 800x18
+        RenderText {TEXT} at (0,0) size 54x18
+          text run at (0,0) width 54: "Success."
+caret: position 0 of child 0 {TEXT} of child 1 {P} of child 1 {BODY} of child 0 {HTML} of document
diff --git a/LayoutTests/fast/text/justified-text-rect.html b/LayoutTests/fast/text/justified-text-rect.html
new file mode 100644 (file)
index 0000000..dd6f2cb
--- /dev/null
@@ -0,0 +1,34 @@
+<html>
+<head>
+<style>
+body { margin: 0; padding: 0 }
+</style>
+</head>
+<body>
+<p contenteditable id='test' STYLE="width: 70px; height: 50px; background-color: green; text-align: justify;">a         a         a</p>
+<script type="text/javascript">
+
+    if (window.layoutTestController) {
+        
+        try {
+        
+            window.getSelection().setPosition(document.getElementById("test"), 0);
+                       
+                       rect = textInputController.firstRectForCharacterRange(10, 1);
+            document.write(rect);
+        
+            // the second character 'a' should be at the right border of the box
+            if (rect[0] > 60)
+               document.write("<p>Success.</p>");
+            else
+               document.write("<p>Failure (rect: " + rect + ")</p>");
+
+               } catch (ex) {
+                       document.write("Exception: " + ex.description);
+               }
+       } else {
+               document.write("(cannot run interactively)");
+       }
+</script>
+</body>
+</html>
index 42261be367828e56ff1d7810cb4f390ac3eb90cc..6e1ab53151940a73d63884ca87001a1185568e23 100644 (file)
@@ -1,3 +1,27 @@
+2005-12-30  Mitz Pettel  <opendarwin.org@mitzpettel.com>
+
+        Reviewed by Darin, landed by ap.
+        
+        Test: fast/text/justified-text-rect.html
+        
+        - WebCore part of fix for
+          http://bugzilla.opendarwin.org/show_bug.cgi?id=5461
+          Text width measured incorrectly when text-align: justify
+
+        * khtml/rendering/font.h:
+        * khtml/rendering/font.cpp:
+        (khtml::Font::selectionRectForText): Added.
+        * khtml/rendering/render_text.cpp:
+        (kthml::InlineTextBox::selectionRect): Use selectionRectForText. This
+        works for justified text as well, and avoids intermediate rounding which
+        resulted in selection rects narrower than AppKit's.
+        (khtml::InlineTextBox::positionForOffset): Use selectionRectForText,
+        which works for justified text as well.
+        * kwq/KWQFontMetrics.h:
+        * kwq/KWQFontMetrics.mm:
+        (QFontMetrics::selectionRectForText): Added.
+        * kwq/WebCoreTextRenderer.h:
+
 2005-12-30  Alexey Proskuryakov  <ap@nypop.com>
 
         - Fix http://bugzilla.opendarwin.org/show_bug.cgi?id=6289
index 5a6fc70f8829aa2bbaba194008b70dafd5b02838..63e2e44480ad75303c9dc1a0e18028e2363e0f05 100644 (file)
 
 namespace khtml {
 
+QRect Font::selectionRectForText(int x, int y, int h, int tabWidth, int xpos, 
+                      QChar *str, int slen, int pos, int len, int toAdd,
+                      bool rtl, bool visuallyOrdered, int from, int to) const
+{
+    return fm.selectionRectForText(x, y, h, tabWidth, xpos, str + pos, std::min(slen - pos, len), from, to, toAdd, rtl, visuallyOrdered, letterSpacing, wordSpacing, fontDef.smallCaps);
+
+}
+
 void Font::drawHighlightForText( QPainter *p, int x, int y, int h, int tabWidth, int xpos, 
                      QChar *str, int slen, int pos, int len,
                      int toAdd, QPainter::TextDirection d, bool visuallyOrdered, int from, int to, QColor bg) const
index eff593fc116c3b814c08cd050190d3575b78548d..0b7310e81d87d53f7dfa7d8b6e6c5524aa645b9c 100644 (file)
@@ -103,7 +103,11 @@ public:
                   QPainter::TextDirection d, bool visuallyOrdered = false, int from = -1, int to = -1, QColor bg = QColor()) const;
     float floatWidth(QChar *str, int slen, int pos, int len, int tabWidth, int xpos) const;
     bool isFixedPitch() const;
-    int checkSelectionPoint(QChar *s, int slen, int pos, int len, int toAdd, int tabWidth, int xpos, int x, QPainter::TextDirection d, bool visuallyOrdered, bool includePartialGlyphs) const;
+    int checkSelectionPoint(QChar *s, int slen, int pos, int len, int toAdd, int tabWidth, int xpos,
+        int x, QPainter::TextDirection d, bool visuallyOrdered, bool includePartialGlyphs) const;
+    QRect selectionRectForText(int x, int y, int h, int tabWidth, int xpos, 
+        QChar *str, int slen, int pos, int len, int width,
+        bool rtl, bool visuallyOrdered = false, int from = -1, int to = -1) const;
     void drawHighlightForText(QPainter *p, int x, int y, int h, int tabWidth, int xpos, 
         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 f9297a149b13e590af1e97d97237fcd7f2fc8359..89f846198cdfb2f65aed41ea7de494a135479ea7 100644 (file)
@@ -123,44 +123,11 @@ QRect InlineTextBox::selectionRect(int tx, int ty, int startPos, int endPos)
 
     RootInlineBox* rootBox = root();
     RenderText* textObj = textObject();
-    int selStart = m_reversed ? m_x + m_width : m_x;
-    int selEnd = selStart;
     int selTop = rootBox->selectionTop();
     int selHeight = rootBox->selectionHeight();
-    int leadWidth = 0;
-
-    // FIXME: For justified text, just return the entire text box's rect.  At the moment there's still no easy
-    // way to get the width of a run including the justification padding.
-    if (sPos > 0 && !m_toAdd) {
-        // The selection begins in the middle of our run.
-        leadWidth = textObj->width(m_start, sPos, textPos(), m_firstLine);
-        if (m_reversed)
-            selStart -= leadWidth;
-        else
-            selStart += leadWidth;
-    }
-
-    if (m_toAdd || (sPos == 0 && ePos == m_len)) {
-        if (m_reversed)
-            selEnd = m_x;
-        else
-            selEnd = m_x + m_width;
-    }
-    else {
-        // Our run is partially selected, and so we need to measure.
-        int w = textObj->width(sPos + m_start, ePos - sPos, textPos() + leadWidth, m_firstLine);
-        if (sPos + m_start > 0 && textObj->str->s[sPos + m_start].isSpace() && !textObj->str->s[sPos + m_start - 1].isSpace())
-            w += textObj->style(m_firstLine)->wordSpacing();
-        if (m_reversed)
-            selEnd = selStart - w;
-        else
-            selEnd = selStart + w;
-    }
-    
-    int selLeft = m_reversed ? selEnd : selStart;
-    int selRight = m_reversed ? selStart : selEnd;
+    const Font *f = textObj->htmlFont(m_firstLine);
 
-    return QRect(selLeft + tx, selTop + ty, selRight - selLeft, selHeight);
+    return f->selectionRectForText(tx + m_x, ty + selTop, selHeight, textObj->tabWidth(), textPos(), textObj->str->s, textObj->str->l, m_start, m_len, m_toAdd, m_reversed, m_dirOverride, sPos, ePos);
 }
 
 void InlineTextBox::deleteLine(RenderArena* arena)
@@ -741,20 +708,11 @@ int InlineTextBox::offsetForPosition(int _x, bool includePartialGlyphs) const
 int InlineTextBox::positionForOffset(int offset) const
 {
     RenderText *text = static_cast<RenderText *>(m_object);
-    const QFontMetrics &fm = text->metrics(m_firstLine);
-
-    int left;
-    if (m_reversed) {
-       int len = m_start + m_len - offset;
-       QString string(text->str->s + offset, len);
-       left = m_x + fm.boundingRect(string, text->tabWidth(), textPos(), len).right();
-    } else {
-       int len = offset - m_start;
-       QString string(text->str->s + m_start, len);
-       left = m_x + fm.boundingRect(string, text->tabWidth(), textPos(), len).right();
-    }
+    const Font *f = text->htmlFont(m_firstLine);
+    int from = m_reversed ? offset - m_start : 0;
+    int to = m_reversed ? m_len : offset - m_start;
     // FIXME: Do we need to add rightBearing here?
-    return left;
+    return f->selectionRectForText(m_x, 0, 0, text->tabWidth(), textPos(), text->str->s, text->str->l, m_start, m_len, m_toAdd, m_reversed, m_dirOverride, from, to).right();
 }
 
 // -------------------------------------------------------------------------------------
index 7ed07b82df4afb2c65a54c99c975a980b011578d..0b3716aa8d37663fb7753e43c3568ab0981d5c1f 100644 (file)
@@ -54,6 +54,10 @@ public:
     int width(const QString &, int tabWidth, int xpos, int len=-1) const;
     int width(const QChar *, int len, int tabWidth, int xpos) const;
     float floatWidth(const QChar *, int slen, int pos, int len, int tabWidth, int xpos, int letterSpacing, int wordSpacing, bool smallCaps) const;
+    QRect selectionRectForText(int x, int y, int h, int tabWidth, int xpos,
+                            const QChar *str, int len, int from, int to, int toAdd,
+                            bool rtl, bool visuallyOrdered, int letterSpacing,
+                            int wordSpacing, bool smallCaps) const;
     int checkSelectionPoint(QChar *s, int slen, int pos, int len, int toAdd, int tabWidth, int xpos, int letterSpacing, int wordSpacing, bool smallCaps, int x, bool reversed, bool dirOverride, bool includePartialGlyphs) const;
 
     QRect boundingRect(QChar) const;
index cb1b75454bde11eecfd241d2c0174c67bfef7051..5a22ee89021fa62a00c6e3d3c9a093001b730362 100644 (file)
@@ -224,6 +224,39 @@ float QFontMetrics::floatWidth(const QChar *uchars, int slen, int pos, int len,
     return [data->getRenderer() floatWidthForRun:&run style:&style];
 }
 
+QRect QFontMetrics::selectionRectForText(int x, int y, int h, int tabWidth, int xpos,
+    const QChar *str, int len, int from, int to, int toAdd,
+    bool rtl, bool visuallyOrdered, int letterSpacing, int wordSpacing, bool smallCaps) const
+{
+    CREATE_FAMILY_ARRAY(data->font(), families);
+
+    if (from < 0)
+        from = 0;
+    if (to < 0)
+        to = len;
+        
+    WebCoreTextRun run;
+    WebCoreInitializeTextRun(&run, (const UniChar *)str, len, from, to);    
+    WebCoreTextStyle style;
+    WebCoreInitializeEmptyTextStyle(&style);
+    style.rtl = rtl;
+    style.directionalOverride = visuallyOrdered;
+    style.letterSpacing = letterSpacing;
+    style.wordSpacing = wordSpacing;
+    style.smallCaps = smallCaps;
+    style.families = families;    
+    style.padding = toAdd;
+    style.tabWidth = tabWidth;
+    style.xpos = xpos;
+    WebCoreTextGeometry geometry;
+    WebCoreInitializeEmptyTextGeometry(&geometry);
+    geometry.point = NSMakePoint(x, y);
+    geometry.selectionY = y;
+    geometry.selectionHeight = h;
+    geometry.useFontMetricsForSelectionYAndHeight = false;
+    return QRect([data->getRenderer() selectionRectForRun:&run style:&style geometry:&geometry]);
+}
+
 int QFontMetrics::checkSelectionPoint(QChar *s, int slen, int pos, int len, int toAdd, int tabWidth, int xpos, int letterSpacing, int wordSpacing, bool smallCaps, int x, bool reversed, bool dirOverride, bool includePartialGlyphs) const
 {
     if (!data) {
index 0805c1ee872039aecf08858816723a4b8a26ca6c..8b919d55b025ad855265b87d625a6f1aaef56bb9 100644 (file)
@@ -94,6 +94,7 @@ extern void WebCoreInitializeEmptyTextGeometry(WebCoreTextGeometry *geometry);
 
 // drawing
 - (void)drawRun:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style geometry:(const WebCoreTextGeometry *)geometry;
+- (NSRect)selectionRectForRun:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style geometry:(const WebCoreTextGeometry *)geometry;
 - (void)drawHighlightForRun:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style geometry:(const WebCoreTextGeometry *)geometry;
 - (void)drawLineForCharacters:(NSPoint)point yOffset:(float)yOffset width: (int)width color:(NSColor *)color thickness:(float)thickness;
 - (void)drawLineForMisspelling:(NSPoint)point withWidth:(int)width;
index fe249eee5b47650cfd5e28dda6e58da3adff4e18..b660c4142acc7da4f8200e4f60d9d5fca200115c 100644 (file)
@@ -1,3 +1,27 @@
+2005-12-30  Mitz Pettel  <opendarwin.org@mitzpettel.com>
+
+        Reviewed by Darin, landed by ap.
+        
+        Test: fast/text/justified-text-rect.html
+        
+        - WebKit part of fix for
+          http://bugzilla.opendarwin.org/show_bug.cgi?id=5461
+          Text width measured incorrectly when text-align: justify
+
+        * WebCoreSupport.subproj/WebTextRenderer.m:
+        (-[WebTextRenderer selectionRectForRun:style:geometry:]): Added.
+        (CG_drawHighlight): Use new function CG_selectionRect.
+        (CG_selectionRect): New function to compute the selection rect.
+        Eliminated rounding hackery that was required for keeping the highlight
+        rect within the selection rect computed by
+        InlineTextBox::selectionRect, since the latter uses this function now.
+        The new selection rect is wider and matches AppKit more closely,
+        although the right hand side is roundf()ed instead of cielf()ed for
+        optimal caret positioning.
+        (ATSU_drawHighlight): Use new function ATSU_selectionRect.
+        (ATSU_selectionRect): New function to compute the selection rect.
+        Much like CG_selectionRect.
+
 2005-12-29  Geoffrey Garen  <ggaren@apple.com>
 
         Reviewed by Eric.
index 98c6b0918cee64eb2dcf03a95b1b2d7470a24217..6c35a502e6a0fa4f8d6d9b54ba7db80fd81b8976 100644 (file)
@@ -144,6 +144,10 @@ static int CG_pointToOffset(WebTextRenderer *, const WebCoreTextRun *, const Web
 static int ATSU_pointToOffset(WebTextRenderer *, const WebCoreTextRun *, const WebCoreTextStyle *,
     int x, bool includePartialGlyphs);
 
+// Selection rect.
+static NSRect CG_selectionRect(WebTextRenderer *, const WebCoreTextRun *, const WebCoreTextStyle *, const WebCoreTextGeometry *);
+static NSRect ATSU_selectionRect(WebTextRenderer *, const WebCoreTextRun *, const WebCoreTextStyle *, const WebCoreTextGeometry *);
+
 // Drawing highlight.
 static void CG_drawHighlight(WebTextRenderer *, const WebCoreTextRun *, const WebCoreTextStyle *, const WebCoreTextGeometry *);
 static void ATSU_drawHighlight(WebTextRenderer *, const WebCoreTextRun *, const WebCoreTextStyle *, const WebCoreTextGeometry *);
@@ -556,6 +560,14 @@ static void destroy(WebTextRenderer *renderer)
     [graphicsContext setShouldAntialias: flag];
 }
 
+- (NSRect)selectionRectForRun:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style geometry:(const WebCoreTextGeometry *)geometry
+{
+    if (shouldUseATSU(run))
+        return ATSU_selectionRect(self, run, style, geometry);
+    else
+        return CG_selectionRect(self, run, style, geometry);
+}
+
 - (void)drawHighlightForRun:(const WebCoreTextRun *)run style:(const WebCoreTextStyle *)style geometry:(const WebCoreTextGeometry *)geometry
 {
     if (shouldUseATSU(run))
@@ -871,7 +883,11 @@ static void CG_drawHighlight(WebTextRenderer *renderer, const WebCoreTextRun * r
         return;
 
     [style->backgroundColor set];
+    [NSBezierPath fillRect:CG_selectionRect(renderer, run, style, geometry)];
+}
 
+static NSRect CG_selectionRect(WebTextRenderer *renderer, const WebCoreTextRun * run, const WebCoreTextStyle *style, const WebCoreTextGeometry *geometry)
+{
     float yPos = geometry->useFontMetricsForSelectionYAndHeight
         ? geometry->point.y - renderer->ascent - (renderer->lineGap / 2) : geometry->selectionY;
     float height = geometry->useFontMetricsForSelectionYAndHeight
@@ -886,20 +902,15 @@ static void CG_drawHighlight(WebTextRenderer *renderer, const WebCoreTextRun * r
     
     advanceWidthIterator(&it, run->from, 0, 0, 0);
     float beforeWidth = it.runWidthSoFar;
-    // apply rounding as if this is the end of the run, since that's how RenderText::selectionRect() works
-    if ((style->applyWordRounding && isRoundingHackCharacter(run->characters[run->from]))
-            || style->applyRunRounding)
-        beforeWidth = ceilf(beforeWidth);
     advanceWidthIterator(&it, run->to, 0, 0, 0);
-    float backgroundWidth = it.runWidthSoFar - beforeWidth;
+    float afterWidth = it.runWidthSoFar;
+    // Using roundf() rather than ceilf() for the right edge as a compromise to ensure correct caret positioning
     if (style->rtl) {
         advanceWidthIterator(&it, run->length, 0, 0, 0);
         float totalWidth = it.runWidthSoFar;
-        if (style->applyRunRounding)
-            totalWidth = ceilf(totalWidth);
-        [NSBezierPath fillRect:NSMakeRect(geometry->point.x + roundf(totalWidth - backgroundWidth - beforeWidth), yPos, roundf(backgroundWidth), height)];
+        return NSMakeRect(geometry->point.x + floorf(totalWidth - afterWidth), yPos, roundf(totalWidth - beforeWidth) - floorf(totalWidth - afterWidth), height);
     } else {
-        [NSBezierPath fillRect:NSMakeRect(geometry->point.x + roundf(beforeWidth), yPos, roundf(backgroundWidth), height)];
+        return NSMakeRect(geometry->point.x + floorf(beforeWidth), yPos, roundf(afterWidth) - floorf(beforeWidth), height);
     }
 }
 
@@ -1457,53 +1468,62 @@ static void ATSU_drawHighlight(WebTextRenderer *renderer, const WebCoreTextRun *
 
     if (style->backgroundColor == nil)
         return;
+    if (run->to <= run->from)
+        return;
     
+    [style->backgroundColor set];
+    [NSBezierPath fillRect:ATSU_selectionRect(renderer, run, style, geometry)];
+}
+
+static NSRect ATSU_selectionRect(WebTextRenderer *renderer, const WebCoreTextRun *run, const WebCoreTextStyle *style, const WebCoreTextGeometry *geometry)
+{
     int from = run->from;
     int to = run->to;
     if (from == -1)
         from = 0;
     if (to == -1)
         to = run->length;
-    int runLength = to - from;
-    if (runLength <= 0)
-        return;
-
-    WebCoreTextRun runWithLead = *run;
-    runWithLead.from = 0;
-    WebCoreTextRun *aRun = &runWithLead;
+        
+    WebCoreTextRun completeRun = *run;
+    completeRun.from = 0;
+    completeRun.to = run->length;
+    
+    WebCoreTextRun *aRun = &completeRun;
     WebCoreTextRun swappedRun;
-
+    
     if (style->directionalOverride) {
         swappedRun = addDirectionalOverride(aRun, style->rtl);
         aRun = &swappedRun;
+        from++;
+        to++;
     }
    
-    float selectedLeftX;
-    float widthWithLead = ATSU_floatWidthForRun(renderer, aRun, style);
+    ATSULayoutParameters params;
+    createATSULayoutParameters(&params, renderer, aRun, style);
     
-    aRun->to -= runLength;
-    float leadWidth = ATSU_floatWidthForRun(renderer, aRun, style);
+    ATSTrapezoid firstGlyphBounds;
+    ItemCount actualNumBounds;
     
-    float backgroundWidth = roundf(widthWithLead - leadWidth);
-
-    if (!style->rtl)
-        selectedLeftX = roundf(geometry->point.x + leadWidth);
-    else {
-        aRun->to += run->length - run->from;
-        float totalWidth = ATSU_floatWidthForRun(renderer, aRun, style);
-        selectedLeftX = roundf(geometry->point.x + totalWidth - widthWithLead);
+    OSStatus status = ATSUGetGlyphBounds(params.layout, 0, 0, from, to - from, kATSUseFractionalOrigins, 1, &firstGlyphBounds, &actualNumBounds);
+    if (status != noErr || actualNumBounds != 1) {
+        static ATSTrapezoid zeroTrapezoid = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
+        firstGlyphBounds = zeroTrapezoid;
     }
+    disposeATSULayoutParameters(&params);    
     
-    [style->backgroundColor set];
-
+    float beforeWidth = MIN(FixedToFloat(firstGlyphBounds.lowerLeft.x), FixedToFloat(firstGlyphBounds.upperLeft.x));
+    float afterWidth = MAX(FixedToFloat(firstGlyphBounds.lowerRight.x), FixedToFloat(firstGlyphBounds.upperRight.x));
     float yPos = geometry->useFontMetricsForSelectionYAndHeight
         ? geometry->point.y - renderer->ascent : geometry->selectionY;
     float height = geometry->useFontMetricsForSelectionYAndHeight
         ? renderer->lineSpacing : geometry->selectionHeight;
-    [NSBezierPath fillRect:NSMakeRect(selectedLeftX, yPos, backgroundWidth, height)];
+
+    NSRect rect = NSMakeRect(geometry->point.x + floorf(beforeWidth), yPos, roundf(afterWidth) - floorf(beforeWidth), height);
 
     if (style->directionalOverride)
         free((void *)swappedRun.characters);
+
+    return rect;
 }