Commit 149606a8 authored by ojan@chromium.org's avatar ojan@chromium.org

Reviewed by Dan Bernstein.

        Make textarea and text input metrics more closely match IEs.

        This involves:
        -set text input width to size*avgCharWidth + maxCharWidth - avgCharWidth
        -set textarea width to cols*avgCharWidth
        -Make default CSS match IEs
        -Correctly initializing m_avgCharWidth and m_maxCharWidth for each platform and SVG.

        Those values for textarea and inputs were derived by doing a ton of manual
        testing of IE's width values for various textareas and fonts. On Windows we match
        IE exactly except for a couple fonts of the ~12 tested.

        To get the average and max character width of a font, we do the following
        for each platform:
        -Win: TextMetrics expose avgCharWidth and maxCharWidth
        -SVG: avgCharWidth = width of an '0', fallback on width of a space glyph, then m_xHeight
            maxCharWidth = width of a 'W' for roman fonts, fallback on m_ascent
        -Linux: avgCharWidth = width of an '0', fallback on m_xHeight
            maxCharWidth = max of avgCharWidth and m_ascent
        -Mac: Calculate the avgCharWidth and grab the maxCharWidth off the font.
            If either one is non-positive, then calculate the value using the Linux approach.

        Tests: fast/forms/text-control-intrinsic-widths.html
               fast/forms/textarea-metrics.html
               svg/custom/svg-fonts-in-text-controls.html

        * css/html4.css:
        * css/themeWin.css:
        * platform/graphics/SimpleFontData.cpp:
        (WebCore::SimpleFontData::SimpleFontData):
        (WebCore::SimpleFontData::initCharWidths):
        * platform/graphics/SimpleFontData.h:
        (WebCore::SimpleFontData::maxCharWidth):
        (WebCore::SimpleFontData::avgCharWidth):
        * platform/graphics/chromium/SimpleFontDataChromiumWin.cpp:
        (WebCore::SimpleFontData::platformCharWidthInit):
        * platform/graphics/chromium/SimpleFontDataLinux.cpp:
        (WebCore::SimpleFontData::platformCharWidthInit):
        * platform/graphics/gtk/SimpleFontDataGtk.cpp:
        (WebCore::SimpleFontData::platformCharWidthInit):
        * platform/graphics/gtk/SimpleFontDataPango.cpp:
        (WebCore::SimpleFontData::platformCharWidthInit):
        * platform/graphics/mac/SimpleFontDataMac.mm:
        (WebCore::SimpleFontData::platformCharWidthInit):
        * platform/graphics/qt/SimpleFontDataQt.cpp:
        (WebCore::SimpleFontData::platformCharWidthInit):
        * platform/graphics/win/SimpleFontDataCGWin.cpp:
        (WebCore::SimpleFontData::platformCharWidthInit):
        * platform/graphics/win/SimpleFontDataCairoWin.cpp:
        (WebCore::SimpleFontData::platformInit):
        (WebCore::SimpleFontData::platformCharWidthInit):
        * platform/graphics/win/SimpleFontDataWin.cpp:
        (WebCore::SimpleFontData::initGDIFont):
        * platform/graphics/wx/SimpleFontDataWx.cpp:
        (WebCore::SimpleFontData::platformCharWidthInit):
        * rendering/RenderTextControl.cpp:
        (WebCore::RenderTextControl::calcPrefWidths):
        * rendering/RenderTextControlMultiLine.cpp:
        (WebCore::RenderTextControlMultiLine::createInnerTextStyle):
        * rendering/RenderTextControlSingleLine.cpp:
        (WebCore::RenderTextControlSingleLine::preferredContentWidth):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@43007 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent b9e6943b
2009-04-28 Ojan Vafai <ojan@chromium.org>
Reviewed by Dan Bernstein.
Make textarea and text input metrics more closely match IEs.
textarea-metrics.js tests the client/scroll/offset width and height
of textareas with various CSS applied to them in both quirks
and strict mode.
svg-fonts-in-text-controls tests that the average and max character
width of an svg font are correctly retrieved.
text-control-intrinsic-widths tests the widths of inputs and textareas with
different size/cols and different fonts set.
Also, there are 3 tests that have Mac-specific metrics in their asserts.
The results are actually correct for Windows, so I've added them
to the Skipped list and promise I'll fix them in the next couple days.
It's just hard to manage a change that requires updating such a large
number of test expectations. The three tests are:
fast/forms/textarea-appearance-wrap.html
fast/forms/textarea-hard-linewrap.html
fast/replaced/table-percent-height.html
Excluding list of updated results as the list is so long.
2009-04-29 Oliver Hunt <oliver@apple.com>
Reviewed by Steve Falkenburg.
This page tests that the tabindex attribute is clamped to values between -32768 and 32767. Values outside of this range should be clamped to the range limits.
Testing input elements in the page
getAttribute("tabindex") = 40000; tabIndex = 32767
getAttribute("tabindex") = 32768; tabIndex = 32767
......
......@@ -3,7 +3,7 @@
function runTest() {
var textarea = document.getElementById("textarea");
var tx = textarea.offsetLeft + textarea.offsetWidth / 2;
var ty = textarea.offsetTop + 2;
var ty = textarea.offsetTop + 4;
var input = document.getElementById("input");
var ix = input.offsetLeft + input.offsetWidth / 2;
......
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
<script src="../../fast/js/resources/js-test-pre.js"></script>
</head>
<body>
<p id="description"></p>
<div id="console"></div>
<script src="YOUR_JS_FILE_HERE"></script>
<script src="../../fast/js/resources/js-test-post.js"></script>
</body>
</html>
description("This test measures the width of textareas and text inputs for different fonts.");
var sizes = [1, 2, 3, 4, 5, 10, 20, 50, 100, 500, 1000];
// This list was grabbed from Wikipedia
// http://en.wikipedia.org/wiki/Core_fonts_for_the_Web
// Impact was removed from the list as not all versions seem to have the same metrics
var ms_web_fonts = ['Andale Mono', 'Arial', 'Comic Sans MS', 'Courier New', 'Georgia',
'Times New Roman', 'Trebuchet MS', 'Verdana', 'Webdings'];
// These are fonts we expect to see installed on all systems.
var fonts = ['Lucida Grande', 'Courier', 'Helvetica', 'Monaco', 'Times'].concat(ms_web_fonts);
function printElementWidth(tagname, font) {
debug('<b>' + tagname + '</b>');
var node = document.createElement(tagname);
node.style.fontFamily = font;
document.body.appendChild(node);
var sizeProperty = tagname == 'input' ? 'size' : 'cols';
for (var i = 0; i < sizes.length; i++) {
node[sizeProperty] = sizes[i];
debug(sizeProperty + '=' + sizes[i] + ' clientWidth=' + node.clientWidth);
}
document.body.removeChild(node);
}
for (var j = 0; j < fonts.length; j++) {
debug('<b>' + fonts[j] + '</b>');
printElementWidth('input', fonts[j]);
debug('')
printElementWidth('textarea', fonts[j]);
debug('');
}
var successfullyParsed = true;
description("This test checks that textareas have the right metrics. These numbers match IE7 except for scrollHeight. For two reasons:<br>" +
"1. scrollHeight is different for elements without enough content to cause scroll because IE7 then reports the height of the text inside the " +
"element as the scrollHeight. IE8 reports has scrollHeight == offsetHeight. Gecko/WebKit have scrollHeight == clientHeight.<br>" +
"2. For the elements with scroll in standards-mode, IE wraps the text differently. It seems to leave 2px less space for the text. We don't " +
"currently mimic this quirk. It's not clear whether we should given that we agree with IE7's clientWidth numbers in all these cases.");
if (window.layoutTestController)
window.layoutTestController.waitUntilDone();
// IE needs some time to get all it's metrics calculated correctly.
// But we don't want to slow down tests when running as run-webkit-tests.
var timeout = window.layoutTestController ? 0 : 100;
var numTextareasLeft = 1;
function assertTextareaMetrics(doc, properties, expectedMetrics) {
var textarea = doc.createElement('textarea');
// Give some consistent CSS for consistent rendering across platforms
// and to help in reasoning when trying to match IE metrics.
var style = 'overflow-y:auto; font-family:Ahem; line-height:20px; height:50px; width:50px;';
var title = '';
for (property in properties) {
var value = properties[property];
title += ' ' + property + ': "' + value + '",';
if (property == 'style')
style += value;
else
textarea[property] = value;
}
textarea.style.cssText = style;
doc.body.appendChild(textarea);
// Create a more human-readable ID.
var id = title.replace(/[\'\",;\:]/g, ' ').replace(/ +/g, '-');
id = id == '' ? 'no-styles' : id;
textarea.id = id;
window[doc.compatMode + 'doc'] = doc;
numTextareasLeft++;
// Give a timeout so IE has time to figure out it's metrics.
setTimeout(function() {
if (!title)
title = ' none';
debug('Properties =' + title);
shouldBe(doc.compatMode + "doc.getElementById('" + id + "').clientWidth", String(expectedMetrics.clientWidth));
shouldBe(doc.compatMode + "doc.getElementById('" + id + "').clientHeight", String(expectedMetrics.clientHeight));
shouldBe(doc.compatMode + "doc.getElementById('" + id + "').offsetWidth", String(expectedMetrics.offsetWidth));
shouldBe(doc.compatMode + "doc.getElementById('" + id + "').offsetHeight", String(expectedMetrics.offsetHeight));
shouldBe(doc.compatMode + "doc.getElementById('" + id + "').scrollWidth", String(expectedMetrics.scrollWidth));
shouldBe(doc.compatMode + "doc.getElementById('" + id + "').scrollHeight", String(expectedMetrics.scrollHeight));
debug('');
numTextareasLeft--;
if (!numTextareasLeft && window.layoutTestController)
window.layoutTestController.notifyDone();
}, timeout);
}
var smallHTML = 'A';
var htmlThatCausesScroll = 'AAAAAAAAA';
function testTextareasForDocument(doc, compatMode,
textareaSizes, textareaWithScrollSizes,
textareaWith8pxPaddingSizes, textareaWith8pxPaddingAndScrollbarSizes) {
if (doc.compatMode != compatMode)
testFailed('This doc should be in ' + compatMode + ' mode.');
try {
var scrollbarStyle = doc.createElement('style');
scrollbarStyle.innerText = 'textarea::-webkit-scrollbar{ width:17px }';
doc.getElementsByTagName('head')[0].appendChild(scrollbarStyle);
} catch (e) {
// IE throws an exception here, but doesn't need the above clause anyways.
}
debug('Testing ' + compatMode + ' document.')
assertTextareaMetrics(doc, {}, textareaSizes);
assertTextareaMetrics(doc, {disabled: true}, textareaSizes);
assertTextareaMetrics(doc, {innerHTML: smallHTML}, textareaSizes);
assertTextareaMetrics(doc, {innerHTML: htmlThatCausesScroll}, textareaWithScrollSizes);
assertTextareaMetrics(doc, {innerHTML: smallHTML, disabled: true}, textareaSizes);
assertTextareaMetrics(doc, {innerHTML: htmlThatCausesScroll, disabled: true}, textareaWithScrollSizes);
assertTextareaMetrics(doc, {innerHTML: smallHTML, style: 'padding:8px'}, textareaWith8pxPaddingSizes);
assertTextareaMetrics(doc, {innerHTML: htmlThatCausesScroll, style: 'padding:8px'}, textareaWith8pxPaddingAndScrollbarSizes);
assertTextareaMetrics(doc, {innerHTML: smallHTML, rows: 10}, textareaSizes);
assertTextareaMetrics(doc, {innerHTML: htmlThatCausesScroll, rows: 10}, textareaWithScrollSizes);
}
// For textareas with scrollbars have the expected clientWidth be the
// expected offsetWidth - scrollbarPlusBorderWidth.
// default border on textareas is 1px solid. So, the border width is 2.
// And the scrollbarWidth we set to be 17 to match windows so that
// these numbers will be platform independent and match IE.
var scrollbarPlusBorderWidth = 19;
var textareaSizesQuirks = {clientWidth: 48,
clientHeight: 48,
offsetWidth: 50,
offsetHeight: 50,
scrollWidth: 48,
scrollHeight: 48};
var textareaWithScrollSizesQuirks = {clientWidth: 50 - scrollbarPlusBorderWidth,
clientHeight: 48,
offsetWidth: 50,
offsetHeight: 50,
scrollWidth: 50 - scrollbarPlusBorderWidth,
scrollHeight: 104};
var textareaWith8pxPaddingSizesQuirks = {clientWidth: 48,
clientHeight: 48,
offsetWidth: 50,
offsetHeight: 50,
scrollWidth: 48,
scrollHeight: 48};
var textareaWith8pxPaddingAndScrollbarSizesQuirks = {clientWidth: 50 - scrollbarPlusBorderWidth,
clientHeight: 48,
offsetWidth: 50,
offsetHeight: 50,
scrollWidth: 50 - scrollbarPlusBorderWidth,
scrollHeight: 196};
testTextareasForDocument(document, 'BackCompat',
textareaSizesQuirks, textareaWithScrollSizesQuirks,
textareaWith8pxPaddingSizesQuirks, textareaWith8pxPaddingAndScrollbarSizesQuirks);
var standardsIframe = document.createElement('iframe');
standardsIframe.style.width = '100%';
document.body.appendChild(standardsIframe);
standardsIframe.contentWindow.document.write('<!DocType html><html><head></head><body></body></html>');
standardsIframe.contentWindow.document.close();
// Give a timeout so IE has time to figure out it's metrics.
setTimeout(function() {
numTextareasLeft--;
var textareaSizesStandards = {clientWidth: 54,
clientHeight: 54,
offsetWidth: 56,
offsetHeight: 56,
scrollWidth: 54,
scrollHeight: 54};
var textareaWithScrollSizesStandards = {clientWidth: 56 - scrollbarPlusBorderWidth,
clientHeight: 54,
offsetWidth: 56,
offsetHeight: 56,
scrollWidth: 56 - scrollbarPlusBorderWidth,
scrollHeight: 64};
var textareaWith8pxPaddingSizesStandards = {clientWidth: 66,
clientHeight: 66,
offsetWidth: 68,
offsetHeight: 68,
scrollWidth: 66,
scrollHeight: 66};
var textareaWith8pxPaddingAndScrollbarSizesStandards = {clientWidth: 68 - scrollbarPlusBorderWidth,
clientHeight: 66,
offsetWidth: 68,