Commit 2734996c authored by ap's avatar ap

Reviewed by Darin, landed by ap.

        - 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: http://svn.webkit.org/repository/webkit/trunk@11846 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 9bbc4e38
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.
......
f711e51f2e376d82b547ae37e94e263b
\ No newline at end of file
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
<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>
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
......
......@@ -33,6 +33,14 @@
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
......
......@@ -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;
......
......@@ -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();
}
// -------------------------------------------------------------------------------------
......
......@@ -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;
......
......@@ -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) {
......
......@@ -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;
......
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.
......@@ -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 @@ - (void)drawLineForCharacters:(NSPoint)point yOffset:(float)yOffset width:(int)w
[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;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment