Open Bug 458617 Opened 16 years ago Updated 2 years ago

div.offsetWidth value WRONG (too small) -- causes text wrapping

Categories

(Core :: DOM: CSS Object Model, defect, P5)

defect

Tracking

()

UNCONFIRMED

People

(Reporter: bugzilla, Unassigned)

References

()

Details

(Keywords: dev-doc-needed, testcase, Whiteboard: WONTFIX?)

Attachments

(4 files)

User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US) AppleWebKit/525.19 (KHTML, like Gecko) Chrome/0.2.153.0 Safari/525.19
Build Identifier: Mozilla/5.0 (Macintosh; U; PPC Mac OS X 10.4; en-US; rv:1.9.0.3) Gecko/2008092414 Firefox/3.0.3

   1. Use font Helvetica with size 8pt
   2. fill a div with text. The div has style position = absolute
   3. let w = the div's offsetWidth attribute value
   4. In a second div, set its width to w
   5. Fill the second div with the exact same text
   6. Problem: On Firefox / Mac, the second div is not wide enough and it wraps the text

The test url shows the problem. The bug ONLY occurs on FF/Mac. No problem with FF/Win, IE6, IE7, Safari/Mac, Safari/Win, Chrome/Win

In other words: div2.style.width = div1.offsetWidth causes div2's text contents to wrap even when div1's text does not wrap. (And they both have the exact same text.)

Reproducible: Always

Steps to Reproduce:
1. See the test file http://simile-widgets.googlecode.com/svn/timeline/trunk/src/webapp/examples/test_example/firefox_mac_test_case.html

2. Appears to require combination of div having position=absolute, font=Helvetica and point size=8. The font/point size combination could simply cause the bug to be triggered with a smaller number of characters. 

Actual Results:  
A div with an explicit width set wraps the text. But the text should not wrap, since the same text does not wrap in the first div.
I think it makes sense that offsetWidth/offsetHeight should return
a value that is large enough to fit the content in this case.
Not sure if this is a regression or not, but it works for me
in Firefox 2.x
Component: General → DOM: Core & HTML
Keywords: testcase
OS: Mac OS X → All
Product: Firefox → Core
QA Contact: general → general
Hardware: Macintosh → All
Summary: Mac only: div.offsetWidth value WRONG (too small) -- causes text wrapping → div.offsetWidth value WRONG (too small) -- causes text wrapping
Attached file Testcase
Attached patch wipSplinter Review
I tried the obvious, use "ceil" instead of "round" in 
nsGenericHTMLElement::GetOffsetRect() and this fixed it, but it broke
a couple of the JQuery width/height tests in
dom/tests/mochitest/ajax/jquery/test/unit/core.js
This is a tough problem. Ideally Web developers would use Math.ceil(elem.getBoundingClientRect().width)...
Attached file Testcase #2
Here's a minimized version of the JQuery test that broke.
The test makes the assumption that if you set the CSS 'width' property
to an integer value you should then have:
CSS width = offsetWidth - Math.round(border + padding)
where border and padding is calculated using
"parseFloat(computedStyle.getPropertyValue( ... ))"

The test appears to work in Opera/Safari since they round the computed
style values for border/padding.
The JQuery test suite seems to use entirely different code path for IE
(IE doesn't seem to support getComputedStyle()).
BTW, here the JQuery code in question:
http://code.google.com/p/jqueryjs/source/browse/trunk/jquery/src/core.js#802

If I follow their code correctly the elem.width() method is implemented
through css(elem, "width", true).
@Mats,

Re: regression

Yes, sorry I forgot to mention: this behavior is a change between FF2/Mac ==> FF3/Mac. In FF2 / Mac the text did not wrap.

Regards,

Larry
(In reply to comment #4)
> This is a tough problem. Ideally Web developers would use
> Math.ceil(elem.getBoundingClientRect().width)...

Yeah, I don't really see any solution to this bug without breaking
something else.  Whatever we do we lose.  So I think we should leave
it as is and suggest better alternatives (as you did).

Would be good to document the fact that offset* are rounded values,
and perhaps even pointing out the specific problem in this bug at MDC:
http://developer.mozilla.org/en/DOM/element.offsetWidth
Keywords: dev-doc-needed
Whiteboard: WONTFIX?
Looking at the code it seems we're rounding scroll* and client* as well,
for documentation...
http://mxr.mozilla.org/seamonkey/source/content/html/content/src/nsGenericHTMLElement.cpp#936
Hmmm, you do realize that this bug only exists in FF version, yes? And that it was introduced sometime between FF 2.0 and 3.0?

If the problem is the jquery test, why does FF / Win pass it? Or if you feel that the jquery test is faulty, can you propose how the jquery test should be improved (and then I'll be happy to submit a bug against the jquery test to them).

Thanks very much for your time and energy on this request and on FF in general. Much appreciated! Regards, Larry
Sorry, what I was trying to say was that this bug is only in FF/Mac, not in FF/Win. So any notes about it would need to be platform-specific.
I'm pretty sure that this issue is a consequence of us supporting subpixel text layout (which we introduced in Firefox 3 on Mac and Linux).

That means you might have a string whose advance width is 10.3px. So its enclosing DIV gets that width. Then its offsetWidth rounds to 10px, but if you set its width to 10px, the string doesn't completely fit anymore so we wrap.

Note that if the user has a high DPI screen or is zoomed in by say 2x, sub-CSS-pixel layout is a very good thing.
Attached file Testcase #3
FWIW, here's a case that also breaks in Firefox 2.
(In reply to comment #11)
> Sorry, what I was trying to say was that this bug is only in FF/Mac, not in
> FF/Win. So any notes about it would need to be platform-specific.

No, I don't think it's Mac-specific.  Just because it happens on Mac
but not on Windows for you doesn't mean this is the case for everyone.
I'm pretty sure we can find cases that breaks on Linux and Windows too,
given the right font and screen DPI.
Windows is different from Mac and Linux because on Windows font metrics are device-pixel aligned, and on Mac and Linux, in Gecko 1.9 and later, they aren't.

But yes, if you zoom in on Windows, or use a high-DPI screen that triggers pixel scaling, you certainly could see this "bug".
I've been looking into the solution suggested above--using Math.ceil(elem.getBoundingClientRect().width) -- and it appears that:

a) Availability: For FF, the method was just introduced in ver 3. FF documentation:
http://developer.mozilla.org/En/DOM/Element.getBoundingClientRect
FF doc says that the method is "Not part of any W3C specification." But it is also in IE 5 and later. IE docs:
http://msdn.microsoft.com/en-us/library/ms536433.aspx

b) The solution from above uses the 'width' property of the returned TextRectangle Object. MS documentation does not show a width property:
http://msdn.microsoft.com/en-us/library/ms535906(VS.85).aspx 

So my plan is to use
// find width
if (elem.getBoundingClientRect != null) {
  var rect = elem.getBoundingClientRect();
  width = Math.ceil(rect.right - rect.left);
} else {
  width = elem.offsetWidth;
}

c) Additional useful comments about getBoundingClientRect
http://www.nczonline.net/blog/2008/02/04/getting-element-dimensions-a-follow-up/
The differences in the root elements' origin don't matter when calculating width and height.

Comments are appreciated.

Larry
getBoundingClientRect is actually part of the CSSOM Views spec:
http://www.w3.org/TR/cssom-view/
I've just updated our docs to mention that. (It's also supported by the latest version of Opera.)

Yeah, using right - left is the way to go. Your code looks good, hope it works for you :-)
https://bugzilla.mozilla.org/show_bug.cgi?id=1472046

Move all DOM bugs that haven’t been updated in more than 3 years and has no one currently assigned to P5.

If you have questions, please contact :mdaly.
Priority: -- → P5
Component: DOM: Core & HTML → DOM: CSS Object Model
Severity: normal → S3
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: