2006-05-13 Sam Weinig <sam.weinig@gmail.com>
authorap <ap@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 13 May 2006 14:58:24 +0000 (14:58 +0000)
committerap <ap@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 13 May 2006 14:58:24 +0000 (14:58 +0000)
        Reviewed by Hyatt, landed by ap.

WebCore:
        Patch for http://bugzilla.opendarwin.org/show_bug.cgi?id=7604
        calcAbsoluteHorizontalValues() is being getting passed arguments
        in the wrong order in calcAbsoluteHorizontal()

        Cleans up the RenderBox code for absolutely positioned elements
        and adds new functions for replaced absolutely positioned
        elements. Now uses Length so that magic number -666666 for
        auto lengths is no longer used.

        * rendering/RenderBox.cpp:
        (WebCore::RenderBox::calcAbsoluteHorizontal):
        (WebCore::RenderBox::calcAbsoluteHorizontalValues):
        (WebCore::RenderBox::calcAbsoluteVertical):
        (WebCore::RenderBox::calcAbsoluteVerticalValues):
        (WebCore::RenderBox::calcAbsoluteHorizontalReplaced): Handle replaced
        case separately.
        (WebCore::RenderBox::calcAbsoluteVerticalReplaced): ditto.
        * rendering/RenderBox.h:

LayoutTests:
        * fast/block/positioning/absolute-length-of-neg-666666.html: Added.
        * fast/block/positioning/absolute-positioned-overconstrained.html: Added.
        * fast/block/positioning/auto/006.html: Updated to reflect that the containing
        block's direction, not the parent's is used.
        * fast/css/absolute-poition-in-rtl-parent.html: Updated and cleaned up.

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

15 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/block/positioning/absolute-length-of-neg-666666-expected.checksum [new file with mode: 0644]
LayoutTests/fast/block/positioning/absolute-length-of-neg-666666-expected.png [new file with mode: 0644]
LayoutTests/fast/block/positioning/absolute-length-of-neg-666666-expected.txt [new file with mode: 0644]
LayoutTests/fast/block/positioning/absolute-length-of-neg-666666.html [new file with mode: 0644]
LayoutTests/fast/block/positioning/absolute-positioned-overconstrained-expected.checksum [new file with mode: 0644]
LayoutTests/fast/block/positioning/absolute-positioned-overconstrained-expected.png [new file with mode: 0644]
LayoutTests/fast/block/positioning/absolute-positioned-overconstrained-expected.txt [new file with mode: 0644]
LayoutTests/fast/block/positioning/absolute-positioned-overconstrained.html [new file with mode: 0644]
LayoutTests/fast/block/positioning/auto/006.html
LayoutTests/fast/css/absolute-poition-in-rtl-parent-expected.txt
LayoutTests/fast/css/absolute-poition-in-rtl-parent.html
WebCore/ChangeLog
WebCore/rendering/RenderBox.cpp
WebCore/rendering/RenderBox.h

index f21f4a881990801b38ed37b300289056fe2a1ab2..9e27f41b9b3fa24abb9e358e7f992a1cf4ec1af8 100644 (file)
@@ -1,3 +1,15 @@
+2006-05-13  Sam Weinig  <sam.weinig@gmail.com>
+
+        Reviewed by Hyatt, landed by ap.
+
+        - tests for http://bugzilla.opendarwin.org/show_bug.cgi?id=7604
+        
+        * fast/block/positioning/absolute-length-of-neg-666666.html: Added.
+        * fast/block/positioning/absolute-positioned-overconstrained.html: Added.
+        * fast/block/positioning/auto/006.html: Updated to reflect that the containing
+        block's direction, not the parent's is used.
+        * fast/css/absolute-poition-in-rtl-parent.html: Updated and cleaned up.
+
 2006-05-12  Mitz Pettel  <opendarwin.org@mitzpettel.com>
 
         Reviewed by Darin.
diff --git a/LayoutTests/fast/block/positioning/absolute-length-of-neg-666666-expected.checksum b/LayoutTests/fast/block/positioning/absolute-length-of-neg-666666-expected.checksum
new file mode 100644 (file)
index 0000000..fff6738
--- /dev/null
@@ -0,0 +1 @@
+5855bbcbb6a2ec7c75e5406af7def470
\ No newline at end of file
diff --git a/LayoutTests/fast/block/positioning/absolute-length-of-neg-666666-expected.png b/LayoutTests/fast/block/positioning/absolute-length-of-neg-666666-expected.png
new file mode 100644 (file)
index 0000000..012aef2
Binary files /dev/null and b/LayoutTests/fast/block/positioning/absolute-length-of-neg-666666-expected.png differ
diff --git a/LayoutTests/fast/block/positioning/absolute-length-of-neg-666666-expected.txt b/LayoutTests/fast/block/positioning/absolute-length-of-neg-666666-expected.txt
new file mode 100644 (file)
index 0000000..f51af19
--- /dev/null
@@ -0,0 +1,13 @@
+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 (8,8) size 784x576
+      RenderBlock {P} at (0,0) size 784x18
+        RenderText {#text} at (0,0) size 579x18
+          text run at (0,0) width 353: "In this test case you should only see one line green text. "
+          text run at (353,0) width 226: "If there is any red the test has failed."
+layer at (8,42) size 128x18
+  RenderBlock (positioned) {DIV} at (0,0) size 128x18 [color=#008000]
+    RenderText {#text} at (0,0) size 128x18
+      text run at (0,0) width 128: "You should see this."
diff --git a/LayoutTests/fast/block/positioning/absolute-length-of-neg-666666.html b/LayoutTests/fast/block/positioning/absolute-length-of-neg-666666.html
new file mode 100644 (file)
index 0000000..45423e0
--- /dev/null
@@ -0,0 +1,20 @@
+<html>
+<head>
+    <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+    <title>Test case for lengths of magic number '-666666'</title>
+    <style type="text/css">
+        #container { position: relative; }
+        #control { position: absolute; margin-left: auto; color: green; }
+        #test1 { position: absolute; top: 1em; margin-left: -666666px; color: red; }
+        #test2 { position: absolute; top: 2em; margin-left: -666665px; color: red; }
+    </style>
+</head>
+<body>
+    <p>In this test case you should only see one line green text.  If there is any red the test has failed.</p>
+    <div id="container">
+        <div id="control">You should see this.</div>
+        <div id="test1">You should not see this!</div>
+        <div id="test2">You should not see this!</div>
+    </div>
+</body>
+</html>
diff --git a/LayoutTests/fast/block/positioning/absolute-positioned-overconstrained-expected.checksum b/LayoutTests/fast/block/positioning/absolute-positioned-overconstrained-expected.checksum
new file mode 100644 (file)
index 0000000..002b301
--- /dev/null
@@ -0,0 +1 @@
+b8f18ee9e15bb5290fbab889ccba6512
\ No newline at end of file
diff --git a/LayoutTests/fast/block/positioning/absolute-positioned-overconstrained-expected.png b/LayoutTests/fast/block/positioning/absolute-positioned-overconstrained-expected.png
new file mode 100644 (file)
index 0000000..ec7fe56
Binary files /dev/null and b/LayoutTests/fast/block/positioning/absolute-positioned-overconstrained-expected.png differ
diff --git a/LayoutTests/fast/block/positioning/absolute-positioned-overconstrained-expected.txt b/LayoutTests/fast/block/positioning/absolute-positioned-overconstrained-expected.txt
new file mode 100644 (file)
index 0000000..6a88a62
--- /dev/null
@@ -0,0 +1,19 @@
+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 (8,8) size 784x584
+      RenderBlock {P} at (0,0) size 784x18
+        RenderText {#text} at (0,0) size 276x18
+          text run at (0,0) width 276: "The two boxes below should look identical."
+      RenderBlock (anonymous) at (0,34) size 784x18
+        RenderText {#text} at (0,0) size 165x18
+          text run at (0,0) width 165: "\\ No newline at end of file"
+layer at (8,42) size 200x200
+  RenderBlock (positioned) {DIV} at (8,42) size 200x200 [bgcolor=#0000FF]
+layer at (8,42) size 100x50
+  RenderBlock (positioned) {DIV} at (0,0) size 100x50 [bgcolor=#008000]
+layer at (300,42) size 200x200
+  RenderBlock (positioned) {DIV} at (300,42) size 200x200 [bgcolor=#0000FF]
+layer at (300,42) size 100x50
+  RenderBlock (positioned) {DIV} at (0,0) size 100x50 [bgcolor=#008000]
diff --git a/LayoutTests/fast/block/positioning/absolute-positioned-overconstrained.html b/LayoutTests/fast/block/positioning/absolute-positioned-overconstrained.html
new file mode 100644 (file)
index 0000000..a77ace0
--- /dev/null
@@ -0,0 +1,39 @@
+<html>
+<head>
+    <title>Over-constrained dimensions test for absolutely positioned elements</title>
+    <style type="text/css">
+        .container {
+            direction: rtl;
+            position: absolute;
+            width: 200px;
+            height: 200px;
+            background-color: blue;
+        }
+        .toTest {
+            position: absolute;
+            /* Over-constrained -- 50px + 75px + 100px + 25px + 25px > 200px */
+            left: 50px;
+            right: 75px;
+            width: 100px;
+            margin-left: 25px;
+            margin-right: 25px;
+
+            height: 50px;
+            background-color: green;
+        }
+        #test { left: 300px; }
+        #control div { direction: ltr; }
+        #test div { direction: rtl; }
+    </style>
+</head>
+<body>
+    <p>The two boxes below should look identical.</p>
+    <div id="control" class="container">
+        <div class="toTest"></div>
+    </div>
+    <div id="test" class="container">
+        <div class="toTest"></div>
+    </div>
+</body>
+</html>
+\ No newline at end of file
index d600012b178982360c689f08da41d8a75806808c..9e0a326d27a808ac14ba84c3d3c51befc8b9399b 100644 (file)
@@ -2,10 +2,10 @@
 <body>
 In this test, you should see three blocks that are aligned right within a black box.  They should
 be stacked vertically with the green box in between two olive boxes.  The olive boxes and the green box
-should be 100x100, and there should be 100 pixels of padding on the right side of the box stack.  
+should be 100x100, and there should be 100 pixels of padding on the left side of the box stack.  
 
-<p style="direction:rtl">The
-black box's top should be aligned with the end of the last line in this parargaph and its left side should begin right after the end of this sentence.
+<p style="position: relative; direction:rtl">The
+black box's top should be aligned with the end of the last line in this parargaph and its right side should begin right after the end of this sentence.
 
  <span style="direction:rtl; position:absolute;width:100px;height:200px;border:20px solid black;padding-top:50px;padding-bottom:50px;padding-left:100px;padding-right:0px">
 <div style="margin-left:800px;position:absolute;margin-top:50px;width:100px;height:100px;background-color:green"></div>
index 011cb9d2168026a5788b0c40308c1da494ac355d..f4b5afeac20d2958453b236322ad6b8f5724ed65 100644 (file)
@@ -6,15 +6,19 @@ layer at (0,0) size 800x600
       RenderBlock {P} at (0,0) size 784x54
         RenderText {#text} at (0,0) size 768x54
           text run at (0,0) width 502: "On the left, you should see three blocks that are aligned left within a black box. "
-          text run at (502,0) width 266: "They should be stacked vertically with the"
+          text run at (502,0) width 83: "They should "
+          text run at (585,0) width 183: "be stacked vertically with the"
           text run at (0,18) width 248: "green box in between two olive boxes. "
-          text run at (248,18) width 502: "The olive boxes and the green box should be 100x100, and there should be 100"
+          text run at (248,18) width 194: "The olive boxes and the green "
+          text run at (442,18) width 308: "box should be 100x100, and there should be 100"
           text run at (0,36) width 322: "pixels of padding on the right side of the box stack."
       RenderBlock {P} at (0,70) size 784x54
         RenderText {#text} at (0,0) size 753x54
           text run at (0,0) width 487: "On the right, you should see two blocks that are centered within a black box. "
-          text run at (487,0) width 266: "They should be stacked vertically with the"
-          text run at (0,18) width 747: "green box below the olive box. The olive box and the green box should be 100x100, and there should be 100 pixels of"
+          text run at (487,0) width 102: "They should be "
+          text run at (589,0) width 164: "stacked vertically with the"
+          text run at (0,18) width 455: "green box below the olive box. The olive box and the green box should "
+          text run at (455,18) width 292: "be 100x100, and there should be 100 pixels of"
           text run at (0,36) width 247: "padding on either side of the box stack."
 layer at (8,148) size 240x340
   RenderBlock (positioned) {DIV} at (8,148) size 240x340 [border: (20px solid #000000)]
@@ -29,7 +33,8 @@ layer at (28,368) size 100x100
   RenderBlock (positioned) {DIV} at (20,220) size 100x100 [bgcolor=#808000]
 layer at (300,148) size 340x240
   RenderBlock (positioned) {DIV} at (300,148) size 340x240 [border: (20px solid #000000)]
-    RenderBlock {DIV} at (20,20) size 200x100
-      RenderBlock {DIV} at (100,0) size 100x100 [bgcolor=#808000]
+layer at (320,168) size 200x100
+  RenderBlock (relative positioned) {DIV} at (20,20) size 200x100
+    RenderBlock {DIV} at (100,0) size 100x100 [bgcolor=#808000]
 layer at (420,268) size 100x100
-  RenderBlock (positioned) {DIV} at (120,120) size 100x100 [bgcolor=#008000]
+  RenderBlock (positioned) {DIV} at (100,100) size 100x100 [bgcolor=#008000]
index 8f55c32c779a3ece61a9b19aebe4701f85eac50b..8bf3ef49ee8f6a0eab68bafae8e18035f2fb03fd 100644 (file)
@@ -1,32 +1,44 @@
 <html>
-<body>
-<p>
-On the left, you should see three blocks that are aligned left within a black box.  They should
-be stacked vertically with the green box in between two olive boxes.  The olive boxes and the green box
-should be 100x100, and there should be 100 pixels of padding on the right side of the box stack.
-</p>
-<p>
-On the right, you should see two blocks that are centered within a black box.  They should be
-stacked vertically with the green box below the olive box. The olive box and the green box should
-be 100x100, and there should be 100 pixels of padding on either side of the box stack.
-</p>
-<div style="position:fixed;width:200px;height:300px;border:20px solid black;">
-<table style="direction:rtl; width:100px;" cellspacing="0" cellpadding="0">
-<tr> 
-<td>
-<div style="width:100px; height:100px; background:olive;"></div>
-<div style="position:absolute; width:100px; height:100px; background:green;"></div>
-<div style="position:absolute; width:100px; height:100px; background:olive; bottom:0; right:100px;"></div>
-</td>
-</tr>
-</table>
-</div>
-<div style="position:fixed;width:300px;height:200px;border:20px solid black; left:300px;">
-<div style="direction:rtl; width:200px;">
-<div style="width:100px; height:100px; background:olive;"></div>
-<div style="position:absolute; width:100px; height:100px; background:green;"></div>
-</div>
-</div>
+<head>
+  <title>Absolute Position in RTL parent</title>
+  <style>
+    .containingBlock { position: fixed; border: 20px solid black; }
+    #cbOne { width: 200px; height: 300px; }
+    #cbOne > table { direction: rtl; width: 100px; }
+    #cbTwo { width: 300px; height: 200px; left: 300px; }
+    #cbTwo > div { position: relative; direction: rtl; width: 200px; }
 
+    .box { width: 100px; height: 100px; }
+    #test1 { background: olive; }
+    #test2 { position: absolute; background: green; }
+    #test3 { position: absolute; bottom: 0; right: 100px; background: olive; }   
+  </style>
+</head>
+<body>
+  <p>On the left, you should see three blocks that are aligned left within a black box.  They should
+    be stacked vertically with the green box in between two olive boxes.  The olive boxes and the green
+    box should be 100x100, and there should be 100 pixels of padding on the right side of the box stack.
+  </p>
+  <p>On the right, you should see two blocks that are centered within a black box.  They should be
+    stacked vertically with the green box below the olive box. The olive box and the green box should
+    be 100x100, and there should be 100 pixels of padding on either side of the box stack.
+  </p>
+  <div id="cbOne" class="containingBlock">
+    <table cellspacing="0" cellpadding="0">
+      <tr> 
+        <td>
+          <div id="test1" class="box"></div>
+          <div id="test2" class="box"></div>
+          <div id="test3" class="box"></div>
+        </td>
+      </tr>
+    </table>
+  </div>
+  <div id="cbTwo" class="containingBlock">
+    <div>
+      <div id="test1" class="box"></div>
+      <div id="test2" class="box"></div>
+    </div>
+  </div>
 </body>
 </html>
index 730d6a18cd0adf1e322ed503c50e3d79617a780d..b8fb31f6c6a594d6c4a9a97df8c242f2b27f5c62 100644 (file)
@@ -1,3 +1,26 @@
+2006-05-13  Sam Weinig  <sam.weinig@gmail.com>
+
+        Reviewed by Hyatt, landed by ap.
+
+        Patch for http://bugzilla.opendarwin.org/show_bug.cgi?id=7604
+        calcAbsoluteHorizontalValues() is being getting passed arguments
+        in the wrong order in calcAbsoluteHorizontal()
+
+        Cleans up the RenderBox code for absolutely positioned elements
+        and adds new functions for replaced absolutely positioned 
+        elements. Now uses Length so that magic number -666666 for 
+        auto lengths is no longer used.
+
+        * rendering/RenderBox.cpp:
+        (WebCore::RenderBox::calcAbsoluteHorizontal):
+        (WebCore::RenderBox::calcAbsoluteHorizontalValues):
+        (WebCore::RenderBox::calcAbsoluteVertical):
+        (WebCore::RenderBox::calcAbsoluteVerticalValues): 
+        (WebCore::RenderBox::calcAbsoluteHorizontalReplaced): Handle replaced
+        case separately.
+        (WebCore::RenderBox::calcAbsoluteVerticalReplaced): ditto.
+        * rendering/RenderBox.h:
+
 2006-05-12  David Hyatt  <hyatt@apple.com>
 
         Bug 8880, remove the remaining drawing/hit testing code from
index 9a43de1e7d9ffdc454dd71410432a65d6a85b73d..80ceceeea8b409404317229d5fde1d5d24e633e9 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
  *           (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
- *           (C) 2005 Samuel Weinig (sam.weinig@gmail.com)
+ *           (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com)
  * Copyright (C) 2005 Apple Computer, Inc.
  *
  * This library is free software; you can redistribute it and/or
 #include "FrameView.h"
 #include "GraphicsContext.h"
 #include "HTMLElement.h"
-#include "RenderTableCell.h"
 #include "HTMLNames.h"
 #include "RenderArena.h"
 #include "RenderCanvas.h"
 #include "RenderFlexibleBox.h"
+#include "RenderTableCell.h"
 #include "RenderTheme.h"
 #include <assert.h>
+#include <algorithm>
 #include <math.h>
 
 using namespace std;
@@ -1414,361 +1415,833 @@ void RenderBox::setStaticY(int staticY)
 
 void RenderBox::calcAbsoluteHorizontal()
 {
-    const int AUTO = -666666;
-    int l, r, cw;
+    if (isReplaced()) {
+        calcAbsoluteHorizontalReplaced();
+        return; 
+    }
 
-    int pab = borderLeft()+ borderRight()+ paddingLeft()+ paddingRight();
 
-    l = r = AUTO;
-    // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
-    RenderObject* cb = container();
-    cw = containingBlockWidth() + cb->paddingLeft() + cb->paddingRight();
+    // QUESTIONS
+    // FIXME 1: Which RenderObject's 'direction' property should used: the
+    // containing block (cb) as the spec seems to imply, the parent (parent()) as
+    // was previously done in calculating the static distances, or ourself, which
+    // was also previously done for deciding what to override when you had
+    // over-constrained margins?  Also note that the container block is used
+    // in similar situations in other parts of the RenderBox class (see calcWidth()
+    // and calcHorizontalMargins()).
 
-    if (!style()->left().isAuto())
-        l = style()->left().calcValue(cw);
-    if (!style()->right().isAuto())
-        r = style()->right().calcValue(cw);
+    // FIXME 2: Should we still deal with these the cases of 'left' or 'right' having
+    // the type 'static' in determining whether to calculate the static distance?
+    // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1.
 
-    int static_distance=0;
-    if ((parent()->style()->direction()==LTR && (l == AUTO && r == AUTO))
-            || style()->left().isStatic())
-    {
-        static_distance = m_staticX - cb->borderLeft(); // Should already have been set through layout of the parent().
-        RenderObject* po = parent();
-        for (; po && po != cb; po = po->parent())
-            static_distance += po->xPos();
+    // FIXME 3: Can perhaps optimize out cases when max-width/min-width are greater
+    // than or less than the computed m_width.  Be careful of box-sizing and
+    // percentage issues.
 
-        l = static_distance;
-    }
+    // The following is based off of the W3C Working Draft from April 11, 2006 of
+    // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements"
+    // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width>
+    // (block-style-comments in this function and in calcAbsoluteHorizontalValues()
+    // correspond to text from the spec)
 
-    else if ((parent()->style()->direction()==RTL && (l==AUTO && r==AUTO ))
-            || style()->right().isStatic())
-    {
-        RenderObject* po = parent();
-        static_distance = m_staticX + cw + cb->borderRight() - po->width(); // Should already have been set through layout of the parent().
-        while (po && po!=containingBlock()) {
-            static_distance -= po->xPos();
-            po=po->parent();
-        }
 
-        r = static_distance;
+    // We don't use containingBlock(), since we may be positioned by an enclosing
+    // relative positioned inline.
+    const RenderObject* containerBlock = container();
+    
+    // FIXME: This is incorrect for cases where the container block is a relatively
+    // positioned inline.
+    const int containerWidth = containingBlockWidth() + containerBlock->paddingLeft() + containerBlock->paddingRight();
+    
+    const int bordersPlusPadding = borderLeft() + borderRight() + paddingLeft() + paddingRight();
+    const Length marginLeft = style()->marginLeft();
+    const Length marginRight = style()->marginRight();
+    Length left = style()->left();
+    Length right = style()->right();
+
+    /*---------------------------------------------------------------------------*\
+     * For the purposes of this section and the next, the term "static position"
+     * (of an element) refers, roughly, to the position an element would have had
+     * in the normal flow. More precisely:
+     *
+     * * The static position for 'left' is the distance from the left edge of the
+     *   containing block to the left margin edge of a hypothetical box that would
+     *   have been the first box of the element if its 'position' property had
+     *   been 'static' and 'float' had been 'none'. The value is negative if the
+     *   hypothetical box is to the left of the containing block.
+     * * The static position for 'right' is the distance from the right edge of the
+     *   containing block to the right margin edge of the same hypothetical box as
+     *   above. The value is positive if the hypothetical box is to the left of the
+     *   containing block's edge.
+     *
+     * But rather than actually calculating the dimensions of that hypothetical box,
+     * user agents are free to make a guess at its probable position.
+     *
+     * For the purposes of calculating the static position, the containing block of
+     * fixed positioned elements is the initial containing block instead of the
+     * viewport, and all scrollable boxes should be assumed to be scrolled to their
+     * origin.
+    \*---------------------------------------------------------------------------*/
+
+    // see FIXME 2
+    // Calculate the static distance if needed.
+    if (left.isAuto() && right.isAuto()) {
+        if (containerBlock->style()->direction() == LTR) {
+            // 'm_staticX' should already have been set through layout of the parent.
+            int staticPosition = m_staticX - containerBlock->borderLeft();
+            for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent())
+                staticPosition += po->xPos();
+            left.setValue(Fixed, staticPosition);
+        } else {
+            RenderObject* po = parent();
+            // 'm_staticX' should already have been set through layout of the parent.
+            int staticPosition = m_staticX + containerWidth + containerBlock->borderRight() - po->width();
+            for (; po && po != containerBlock; po = po->parent())
+                staticPosition -= po->xPos();
+            right.setValue(Fixed, staticPosition);
+        }
     }
 
-    calcAbsoluteHorizontalValues(Width, cb, cw, pab, static_distance, l, r, m_width, m_marginLeft, m_marginRight, m_x);
+    // Calculate constraint equation values for 'width' case.
+    calcAbsoluteHorizontalValues(style()->width(), containerBlock, containerWidth, bordersPlusPadding,
+                                 left, right, marginLeft, marginRight,
+                                 m_width, m_marginLeft, m_marginRight, m_x);
 
-    // Avoid doing any work in the common case (where the values of min-width and max-width are their defaults).
-    int minW = m_width, minML, minMR, minX;
-    calcAbsoluteHorizontalValues(MinWidth, cb, cw, pab, static_distance, l, r, minW, minML, minMR, minX);
+    // Calculate constraint equation values for 'max-width' case.calcContentBoxWidth(width.calcValue(containerWidth));
+    if (style()->maxWidth().value() != undefinedLength) {
+        int maxWidth;
+        int maxMarginLeft;
+        int maxMarginRight;
+        int maxXPos;
 
-    int maxW = m_width, maxML, maxMR, maxX;
-    if (style()->maxWidth().value() != undefinedLength)
-        calcAbsoluteHorizontalValues(MaxWidth, cb, cw, static_distance, pab, l, r, maxW, maxML, maxMR, maxX);
+        calcAbsoluteHorizontalValues(style()->maxWidth(), containerBlock, containerWidth, bordersPlusPadding,
+                                     left, right, marginLeft, marginRight,
+                                     maxWidth, maxMarginLeft, maxMarginRight, maxXPos);
 
-    if (m_width > maxW) {
-        m_width = maxW;
-        m_marginLeft = maxML;
-        m_marginRight = maxMR;
-        m_x = maxX;
-    }
-    
-    if (m_width < minW) {
-        m_width = minW;
-        m_marginLeft = minML;
-        m_marginRight = minMR;
-        m_x = minX;
+        if (m_width > maxWidth) {
+            m_width = maxWidth;
+            m_marginLeft = maxMarginLeft;
+            m_marginRight = maxMarginRight;
+            m_x = maxXPos;
+        }
     }
-}
 
-void RenderBox::calcAbsoluteHorizontalValues(WidthType widthType, RenderObject* cb, int cw, int pab, int static_distance,
-                                             int l, int r, int& w, int& ml, int& mr, int& x)
-{
-    const int AUTO = -666666;
-    w = ml = mr = AUTO;
+    // Calculate constraint equation values for 'min-width' case.
+    if (style()->minWidth().value()) {
+        int minWidth;
+        int minMarginLeft;
+        int minMarginRight;
+        int minXPos;
 
-    if (!style()->marginLeft().isAuto())
-        ml = style()->marginLeft().calcValue(cw);
-    if (!style()->marginRight().isAuto())
-        mr = style()->marginRight().calcValue(cw);
+        calcAbsoluteHorizontalValues(style()->minWidth(), containerBlock, containerWidth, bordersPlusPadding,
+                                     left, right, marginLeft, marginRight,
+                                     minWidth, minMarginLeft, minMarginRight, minXPos);
 
-    Length width;
-    if (widthType == Width)
-        width = style()->width();
-    else if (widthType == MinWidth)
-        width = style()->minWidth();
-    else
-        width = style()->maxWidth();
-
-    if (!width.isIntrinsicOrAuto())
-        w = calcContentBoxWidth(width.calcValue(cw));
-    else if (isReplaced())
-        w = calcReplacedWidth();
-
-    if (l != AUTO && w != AUTO && r != AUTO) {
-        // left, width, right all given, play with margins
-        int ot = l + w + r + pab;
-
-        if (ml==AUTO && mr==AUTO) {
-            // both margins auto, solve for equality
-            ml = (cw - ot)/2;
-            mr = cw - ot - ml;
-        }
-        else if (ml==AUTO)
-            // solve for left margin
-            ml = cw - ot - mr;
-        else if (mr==AUTO)
-            // solve for right margin
-            mr = cw - ot - ml;
-        else {
-            // overconstrained, solve according to dir
-            if (style()->direction() == LTR)
-                r = cw - ( l + w + ml + mr + pab);
-            else
-                l = cw - ( r + w + ml + mr + pab);
+        if (m_width < minWidth) {
+            m_width = minWidth;
+            m_marginLeft = minMarginLeft;
+            m_marginRight = minMarginRight;
+            m_x = minXPos;
         }
     }
-    else
-    {
-        // one or two of (left, width, right) missing, solve
-
-        // auto margins are ignored
-        if (ml==AUTO) ml = 0;
-        if (mr==AUTO) mr = 0;
-
-        //1. solve left & width.
-        if (l == AUTO && w == AUTO && r != AUTO) {
-            // From section 10.3.7 of the CSS2.1 specification.
-            // "The shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width)."
-            w = min(max(m_minWidth - pab, cw - (r + ml + mr + pab)), m_maxWidth - pab);
-            l = cw - (r + w + ml + mr + pab);
-        }
-        else
 
-        //2. solve left & right. use static positioning.
-        if (l == AUTO && w != AUTO && r == AUTO) {
-            if (style()->direction()==RTL) {
-                r = static_distance;
-                l = cw - (r + w + ml + mr + pab);
-            }
-            else {
-                l = static_distance;
-                r = cw - (l + w + ml + mr + pab);
+    // Put m_width into correct form.
+    m_width += bordersPlusPadding;
+}
+
+void RenderBox::calcAbsoluteHorizontalValues(Length width, const RenderObject* containerBlock,
+                                             const int containerWidth, const int bordersPlusPadding,
+                                             const Length left, const Length right, const Length marginLeft, const Length marginRight,
+                                             int& widthValue, int& marginLeftValue, int& marginRightValue, int& xPos)
+{
+    // 'left' and 'right' cannot both be 'auto' because one would of been
+    // converted to the static postion already
+    ASSERT(!(left.isAuto() && right.isAuto()));
+
+    int leftValue;
+
+    bool widthIsAuto = width.isIntrinsicOrAuto();
+    bool leftIsAuto = left.isAuto();
+    bool rightIsAuto = right.isAuto();
+
+    if (!leftIsAuto && !widthIsAuto && !rightIsAuto) {
+        /*-----------------------------------------------------------------------*\
+         * If none of the three is 'auto': If both 'margin-left' and 'margin-
+         * right' are 'auto', solve the equation under the extra constraint that
+         * the two margins get equal values, unless this would make them negative,
+         * in which case when direction of the containing block is 'ltr' ('rtl'),
+         * set 'margin-left' ('margin-right') to zero and solve for 'margin-right'
+         * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto',
+         * solve the equation for that value. If the values are over-constrained,
+         * ignore the value for 'left' (in case the 'direction' property of the
+         * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr')
+         * and solve for that value.
+        \*-----------------------------------------------------------------------*/
+        // NOTE:  It is not necessary to solve for 'right' in the over constrained
+        // case because the value is not used for any further calculations.
+
+        leftValue = left.calcValue(containerWidth);
+        widthValue = calcContentBoxWidth(width.calcValue(containerWidth));
+
+        const int availableSpace = containerWidth - (leftValue + widthValue + right.calcValue(containerWidth) + bordersPlusPadding);
+
+        // Margins are now the only unknown
+        if (marginLeft.isAuto() && marginRight.isAuto()) {
+            // Both margins auto, solve for equality
+            if (availableSpace >= 0) {
+                marginLeftValue = availableSpace / 2; // split the diference
+                marginRightValue = availableSpace - marginLeftValue;  // account for odd valued differences
+            } else {
+                // see FIXME 1
+                if (containerBlock->style()->direction() == LTR) {
+                    marginLeftValue = 0;
+                    marginRightValue = availableSpace; // will be negative
+                } else {
+                    marginLeftValue = availableSpace; // will be negative
+                    marginRightValue = 0;
+                }
             }
+        } else if (marginLeft.isAuto()) {
+            // Solve for left margin
+            marginRightValue = marginRight.calcValue(containerWidth);
+            marginLeftValue = availableSpace - marginRightValue;
+        } else if (marginRight.isAuto()) {
+            // Solve for right margin
+            marginLeftValue = marginLeft.calcValue(containerWidth);
+            marginRightValue = availableSpace - marginLeftValue;
+        } else {
+            // Over-constrained, solve for left if direction is RTL
+            marginLeftValue = marginLeft.calcValue(containerWidth);
+            marginRightValue = marginRight.calcValue(containerWidth);
 
-        } //3. solve width & right.
-        else if (l != AUTO && w == AUTO && r == AUTO) {
-            // From section 10.3.7 of the CSS2.1 specification.
-            // "The shrink-to-fit width is: min(max(preferred minimum width, available width), preferred width)."
-            w = min(max(m_minWidth - pab, cw - (l + ml + mr + pab)), m_maxWidth - pab);
-            r = cw - (l + w + ml + mr + pab);
+            // see FIXME 1 -- used to be "this->style()->direction()"
+            if (containerBlock->style()->direction() == RTL)
+                leftValue = (availableSpace + leftValue) - marginLeftValue - marginRightValue;
+        }
+    } else {
+        /*--------------------------------------------------------------------*\
+         * Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
+         * to 0, and pick the one of the following six rules that applies.
+         *
+         * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the
+         *    width is shrink-to-fit. Then solve for 'left'
+         *
+         *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
+         * ------------------------------------------------------------------
+         * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if
+         *    the 'direction' property of the containing block is 'ltr' set
+         *    'left' to the static position, otherwise set 'right' to the
+         *    static position. Then solve for 'left' (if 'direction is 'rtl')
+         *    or 'right' (if 'direction' is 'ltr').
+         * ------------------------------------------------------------------
+         *
+         * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the
+         *    width is shrink-to-fit . Then solve for 'right'
+         * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve
+         *    for 'left'
+         * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve
+         *    for 'width'
+         * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve
+         *    for 'right'
+         *
+         * Calculation of the shrink-to-fit width is similar to calculating the
+         * width of a table cell using the automatic table layout algorithm.
+         * Roughly: calculate the preferred width by formatting the content
+         * without breaking lines other than where explicit line breaks occur,
+         * and also calculate the preferred minimum width, e.g., by trying all
+         * possible line breaks. CSS 2.1 does not define the exact algorithm.
+         * Thirdly, calculate the available width: this is found by solving
+         * for 'width' after setting 'left' (in case 1) or 'right' (in case 3)
+         * to 0.
+         *
+         * Then the shrink-to-fit width is:
+         * min(max(preferred minimum width, available width), preferred width).
+        \*--------------------------------------------------------------------*/
+        // NOTE: For rules 3 and 6 it is not necessary to solve for 'right'
+        // because the value is not used for any further calculations.
+
+        // Calculate margins, 'auto' margins are ignored.
+        marginLeftValue = marginLeft.calcMinValue(containerWidth);
+        marginRightValue = marginRight.calcMinValue(containerWidth);
+
+        const int availableSpace = containerWidth - (marginLeftValue + marginRightValue + bordersPlusPadding);
+
+        // FIXME: Is there a faster way to find the correct case?
+        // Use rule/case that applies.
+        if (leftIsAuto && widthIsAuto && !rightIsAuto) {
+            // RULE 1: (use shrink-to-fit for width, and solve of left)
+            int rightValue = right.calcValue(containerWidth);
+
+            // FIXME: would it be better to have shrink-to-fit in one step?
+            int preferredWidth = m_maxWidth - bordersPlusPadding;
+            int preferredMinWidth = m_minWidth - bordersPlusPadding;
+            int availableWidth = availableSpace - rightValue;
+            widthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
+            leftValue = availableSpace - (widthValue + rightValue);
+        } else if (!leftIsAuto && widthIsAuto && rightIsAuto) {
+            // RULE 3: (use shrink-to-fit for width, and no need solve of right)
+            leftValue = left.calcValue(containerWidth);
+
+            // FIXME: would it be better to have shrink-to-fit in one step?
+            int preferredWidth = m_maxWidth - bordersPlusPadding;
+            int preferredMinWidth = m_minWidth - bordersPlusPadding;
+            int availableWidth = availableSpace - leftValue;
+            widthValue = min(max(preferredMinWidth, availableWidth), preferredWidth);
+        } else if (leftIsAuto && !width.isAuto() && !rightIsAuto) {
+            // RULE 4: (solve for left)
+            widthValue = calcContentBoxWidth(width.calcValue(containerWidth));
+            leftValue = availableSpace - (widthValue + right.calcValue(containerWidth));
+        } else if (!leftIsAuto && widthIsAuto && !rightIsAuto) {
+            // RULE 5: (solve for width)
+            leftValue = left.calcValue(containerWidth);
+            widthValue = availableSpace - (leftValue + right.calcValue(containerWidth));
+        } else if (!leftIsAuto&& !widthIsAuto && rightIsAuto) {
+            // RULE 6: (no need solve for right)
+            leftValue = left.calcValue(containerWidth);
+            widthValue = calcContentBoxWidth(width.calcValue(containerWidth));
         }
-        else
-
-        //4. solve left
-        if (l==AUTO && w!=AUTO && r!=AUTO)
-            l = cw - (r + w + ml + mr + pab);
-        else
-        //5. solve width
-        if (l!=AUTO && w==AUTO && r!=AUTO)
-            w = cw - (r + l + ml + mr + pab);
-        else
-
-        //6. solve right
-        if (l!=AUTO && w!=AUTO && r==AUTO)
-            r = cw - (l + w + ml + mr + pab);
     }
 
-    w += pab;
-    x = l + ml + cb->borderLeft();
+    // Use computed values to calculate the horizontal position.
+    xPos = leftValue + marginLeftValue + containerBlock->borderLeft();
 }
 
 void RenderBox::calcAbsoluteVertical()
 {
-    // css2 spec 10.6.4 & 10.6.5
+    if (isReplaced()) {
+        calcAbsoluteVerticalReplaced();
+        return;
+    }
+
+    // The following is based off of the W3C Working Draft from April 11, 2006 of
+    // CSS 2.1: Section 10.6.4 "Absolutely positioned, non-replaced elements"
+    // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-non-replaced-height>
+    // (block-style-comments in this function and in calcAbsoluteVerticalValues()
+    // correspond to text from the spec)
 
-    // based on
-    // http://www.w3.org/Style/css2-updates/REC-CSS2-19980512-errata
-    // (actually updated 2000-10-24)
-    // that introduces static-position value for top, left & right
 
-    const int AUTO = -666666;
-    int t, b, ch;
+    // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
+    const RenderObject* containerBlock = container();
 
-    t = b = AUTO;
+    // Even in strict mode (where we don't grow the root to fill the viewport) other browsers
+    // position as though the root fills the viewport.
+    const int containerHeight = containerBlock->isRoot() ? containerBlock->availableHeight() : (containerBlock->height() - containerBlock->borderTop() - containerBlock->borderBottom());
+    
+    const int bordersPlusPadding = borderTop() + borderBottom() + paddingTop() + paddingBottom();
+    const Length marginTop = style()->marginTop();
+    const Length marginBottom = style()->marginBottom();
+    Length top = style()->top();
+    Length bottom = style()->bottom();
+
+    /*---------------------------------------------------------------------------*\
+     * For the purposes of this section and the next, the term "static position"
+     * (of an element) refers, roughly, to the position an element would have had
+     * in the normal flow. More precisely, the static position for 'top' is the
+     * distance from the top edge of the containing block to the top margin edge
+     * of a hypothetical box that would have been the first box of the element if
+     * its 'position' property had been 'static' and 'float' had been 'none'. The
+     * value is negative if the hypothetical box is above the containing block.
+     *
+     * But rather than actually calculating the dimensions of that hypothetical
+     * box, user agents are free to make a guess at its probable position.
+     *
+     * For the purposes of calculating the static position, the containing block
+     * of fixed positioned elements is the initial containing block instead of
+     * the viewport.
+    \*---------------------------------------------------------------------------*/
+
+    // see FIXME 2
+    // Calculate the static distance if needed.
+    if (top.isAuto() && bottom.isAuto()) {
+        // m_staticY should already have been set through layout of the parent()
+        int staticTop = m_staticY - containerBlock->borderTop();
+        for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) {
+            if (!po->isTableRow())
+                staticTop += po->yPos();
+        }
+        top.setValue(Fixed, staticTop);
+    }
 
-    int pab = borderTop()+borderBottom()+paddingTop()+paddingBottom();
 
-    // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
-    RenderObject* cb = container();
-    if (cb->isRoot()) // Even in strict mode (where we don't grow the root to fill the viewport) other browsers
-                      // position as though the root fills the viewport.
-        ch = cb->availableHeight();
-    else
-        ch = cb->height() - cb->borderTop() - cb->borderBottom();
+    int height; // Needed to compute overflow.
 
-    if (!style()->top().isAuto())
-        t = style()->top().calcValue(ch);
-    if (!style()->bottom().isAuto())
-        b = style()->bottom().calcValue(ch);
+    // Calculate constraint equation values for 'height' case.
+    calcAbsoluteVerticalValues(style()->height(), containerBlock, containerHeight, bordersPlusPadding,
+                               top, bottom, marginTop, marginBottom,
+                               height, m_marginTop, m_marginBottom, m_y);
 
-    int h, mt, mb, y;
-    calcAbsoluteVerticalValues(Height, cb, ch, pab, t, b, h, mt, mb, y);
+    // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).    
+    // see FIXME 3
 
-    // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults).
-    int minH = h, minMT, minMB, minY;
-    calcAbsoluteVerticalValues(MinHeight, cb, ch, pab, t, b, minH, minMT, minMB, minY);
+    // Calculate constraint equation values for 'max-height' case.
+    if (style()->maxHeight().value() != undefinedLength) {
+        int maxHeight;
+        int maxMarginTop;
+        int maxMarginBottom;
+        int maxYPos;
 
-    int maxH = h, maxMT, maxMB, maxY;
-    if (style()->maxHeight().value() != undefinedLength)
-        calcAbsoluteVerticalValues(MaxHeight, cb, ch, pab, t, b, maxH, maxMT, maxMB, maxY);
+        calcAbsoluteVerticalValues(style()->maxHeight(), containerBlock, containerHeight, bordersPlusPadding,
+                                   top, bottom, marginTop, marginBottom,
+                                   maxHeight, maxMarginTop, maxMarginBottom, maxYPos);
 
-    if (h > maxH) {
-        h = maxH;
-        mt = maxMT;
-        mb = maxMB;
-        y = maxY;
+        if (height > maxHeight) {
+            height = maxHeight;
+            m_marginTop = maxMarginTop;
+            m_marginBottom = maxMarginBottom;
+            m_y = maxYPos;
+        }
     }
-    
-    if (h < minH) {
-        h = minH;
-        mt = minMT;
-        mb = minMB;
-        y = minY;
+
+    // Calculate constraint equation values for 'min-height' case.
+    if (style()->minHeight().value()) {
+        int minHeight;
+        int minMarginTop;
+        int minMarginBottom;
+        int minYPos;
+
+        calcAbsoluteVerticalValues(style()->minHeight(), containerBlock, containerHeight, bordersPlusPadding,
+                                   top, bottom, marginTop, marginBottom,
+                                   minHeight, minMarginTop, minMarginBottom, minYPos);
+
+        if (height < minHeight) {
+            height = minHeight;
+            m_marginTop = minMarginTop;
+            m_marginBottom = minMarginBottom;
+            m_y = minYPos;
+        }
     }
-    
-    // If our natural height exceeds the new height once we've set it, then we need to make sure to update
-    // overflow to track the spillout.
-    if (m_height > h)
+
+    // If our natural height exceeds the new height once we've set it, then we
+    // need to make sure to update overflow to track the spillout.
+    if (m_height > height)
         setOverflowHeight(m_height);
-        
-    // Set our final values.
-    m_height = h;
-    m_marginTop = mt;
-    m_marginBottom = mb;
-    m_y = y;
+
+    // Set final height value.
+    m_height = height;
 }
 
-void RenderBox::calcAbsoluteVerticalValues(HeightType heightType, RenderObject* cb, int ch, int pab, 
-                                           int t, int b, int& h, int& mt, int& mb, int& y)
+void RenderBox::calcAbsoluteVerticalValues(Length height, const RenderObject* containerBlock,
+                                           const int containerHeight, const int bordersPlusPadding,
+                                           const Length top, const Length bottom, const Length marginTop, const Length marginBottom,
+                                           int& heightValue, int& marginTopValue, int& marginBottomValue, int& yPos)
 {
-    const int AUTO = -666666;
-    h = mt = mb = AUTO;
-
-    if (!style()->marginTop().isAuto())
-        mt = style()->marginTop().calcValue(ch);
-    if (!style()->marginBottom().isAuto())
-        mb = style()->marginBottom().calcValue(ch);
-
-    Length height;
-    if (heightType == Height)
-        height = style()->height();
-    else if (heightType == MinHeight)
-        height = style()->minHeight();
-    else
-        height = style()->maxHeight();
+    // 'top' and 'bottom' cannot both be 'auto' because 'top would of been
+    // converted to the static position in calcAbsoluteVertical()
+    ASSERT(!(top.isAuto() && bottom.isAuto()));
+
+    int contentHeight = m_height - bordersPlusPadding;    
+
+    int topValue;
+
+    bool heightIsAuto = height.isAuto();
+    bool topIsAuto = top.isAuto();
+    bool bottomIsAuto = bottom.isAuto();
+
+    // Height is never unsolved for tables.
+    if (isTable() && heightIsAuto) {
+        height.setValue(Fixed, contentHeight);
+        heightIsAuto = false;
+    } else if (!heightIsAuto)
+        contentHeight = min(contentHeight, calcContentBoxHeight(height.calcValue(containerHeight)));
+
+    if (!topIsAuto && !heightIsAuto && !bottomIsAuto) {
+        /*-----------------------------------------------------------------------*\
+         * If none of the three are 'auto': If both 'margin-top' and 'margin-
+         * bottom' are 'auto', solve the equation under the extra constraint that
+         * the two margins get equal values. If one of 'margin-top' or 'margin-
+         * bottom' is 'auto', solve the equation for that value. If the values
+         * are over-constrained, ignore the value for 'bottom' and solve for that
+         * value.
+        \*-----------------------------------------------------------------------*/
+        // NOTE:  It is not necessary to solve for 'bottom' in the over constrained
+        // case because the value is not used for any further calculations.
+
+        heightValue = calcContentBoxHeight(height.calcValue(containerHeight));
+        topValue = top.calcValue(containerHeight);
+
+        const int availableSpace = containerHeight - (topValue + heightValue + bottom.calcValue(containerHeight) + bordersPlusPadding);
+
+        // Margins are now the only unknown
+        if (marginTop.isAuto() && marginBottom.isAuto()) {
+            // Both margins auto, solve for equality
+            // NOTE: This may result in negative values.
+            marginTopValue = availableSpace / 2; // split the diference
+            marginBottomValue = availableSpace - marginTopValue; // account for odd valued differences
+        } else if (marginTop.isAuto()) {
+            // Solve for top margin
+            marginBottomValue = marginBottom.calcValue(containerHeight);
+            marginTopValue = availableSpace - marginBottomValue;
+        } else if (marginBottom.isAuto()) {
+            // Solve for bottom margin
+            marginTopValue = marginTop.calcValue(containerHeight);
+            marginBottomValue = availableSpace - marginTopValue;
+        } else {
+            // Over-constrained, (no need solve for bottom)
+            marginTopValue = marginTop.calcValue(containerHeight);
+            marginBottomValue = marginBottom.calcValue(containerHeight);
+        }
+    } else {
+        /*--------------------------------------------------------------------*\
+         * Otherwise, set 'auto' values for 'margin-top' and 'margin-bottom'
+         * to 0, and pick the one of the following six rules that applies.
+         *
+         * 1. 'top' and 'height' are 'auto' and 'bottom' is not 'auto', then 
+         *    the height is based on the content, and solve for 'top'.
+         *
+         *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
+         * ------------------------------------------------------------------
+         * 2. 'top' and 'bottom' are 'auto' and 'height' is not 'auto', then
+         *    set 'top' to the static position, and solve for 'bottom'.
+         * ------------------------------------------------------------------
+         *
+         * 3. 'height' and 'bottom' are 'auto' and 'top' is not 'auto', then
+         *    the height is based on the content, and solve for 'bottom'.
+         * 4. 'top' is 'auto', 'height' and 'bottom' are not 'auto', and
+         *    solve for 'top'.
+         * 5. 'height' is 'auto', 'top' and 'bottom' are not 'auto', and
+         *    solve for 'height'.
+         * 6. 'bottom' is 'auto', 'top' and 'height' are not 'auto', and
+         *    solve for 'bottom'.
+        \*--------------------------------------------------------------------*/
+        // NOTE: For rules 3 and 6 it is not necessary to solve for 'bottom'
+        // because the value is not used for any further calculations.
+
+        // Calculate margins, 'auto' margins are ignored.
+        marginTopValue = marginTop.calcMinValue(containerHeight);
+        marginBottomValue = marginBottom.calcMinValue(containerHeight);
+
+        const int availableSpace = containerHeight - (marginTopValue + marginBottomValue + bordersPlusPadding);
+
+        // Use rule/case that applies.
+        if (topIsAuto && heightIsAuto && !bottomIsAuto) {
+            // RULE 1: (height is content based, solve of top)
+            heightValue = contentHeight;
+            topValue = availableSpace - (heightValue + bottom.calcValue(containerHeight));
+        } else if (!topIsAuto && heightIsAuto && bottomIsAuto) {
+            // RULE 3: (height is content based, no need solve of bottom)
+            topValue = top.calcValue(containerHeight);
+            heightValue = contentHeight;
+        } else if (topIsAuto && !heightIsAuto && !bottomIsAuto) {
+            // RULE 4: (solve of top)
+            heightValue = calcContentBoxHeight(height.calcValue(containerHeight));
+            topValue = availableSpace - (heightValue + bottom.calcValue(containerHeight));
+        } else if (!topIsAuto && heightIsAuto && !bottomIsAuto) {
+            // RULE 5: (solve of height)
+            topValue = top.calcValue(containerHeight);
+            heightValue = availableSpace - (topValue + bottom.calcValue(containerHeight));
+        } else if (!topIsAuto && !heightIsAuto && bottomIsAuto) {
+            // RULE 6: (no need solve of bottom)
+            heightValue = calcContentBoxHeight(height.calcValue(containerHeight));
+            topValue = top.calcValue(containerHeight);
+        }
+    }
 
-    int ourHeight = m_height;
+    // Make final adjustments to height.
+    if (!(contentHeight < heightValue) && !(hasOverflowClip() && contentHeight > heightValue))
+        heightValue = contentHeight;
 
-    if (isTable() && height.isAuto())
-        // Height is never unsolved for tables. "auto" means shrink to fit.  Use our
-        // height instead.
-        h = ourHeight - pab;
-    else if (!height.isAuto())
-    {
-        h = calcContentBoxHeight(height.calcValue(ch));
-        if (ourHeight - pab > h)
-            ourHeight = h + pab;
-    }
-    else if (isReplaced())
-        h = calcReplacedHeight();
-
-    int static_top=0;
-    if ((t == AUTO && b == AUTO) || style()->top().isStatic()) {
-        // calc hypothetical location in the normal flow
-        // used for 1) top=static-position
-        //          2) top, bottom, height are all auto -> calc top -> 3.
-        //          3) precalc for case 2 below
-        static_top = m_staticY - cb->borderTop(); // Should already have been set through layout of the parent().
-        RenderObject* po = parent();
-        for (; po && po != cb; po = po->parent())
-            if (!po->isTableRow())
-                static_top += po->yPos();
+    // Do not allow the height to be negative.  This can happen when someone
+    // specifies both top and bottom but the containing block height is less
+    // than top, e.g., top: 20px, bottom: 0, containing block height 16.
+    heightValue = max(0, heightValue + bordersPlusPadding);
 
-        if (h == AUTO || style()->top().isStatic())
-            t = static_top;
-    }
+    // Use computed values to calculate the vertical position.
+    yPos = topValue + marginTopValue + containerBlock->borderTop();
+}
 
-    if (t != AUTO && h != AUTO && b != AUTO) {
-        // top, height, bottom all given, play with margins
-        int ot = h + t + b + pab;
+void RenderBox::calcAbsoluteHorizontalReplaced()
+{   
+    // The following is based off of the W3C Working Draft from April 11, 2006 of
+    // CSS 2.1: Section 10.3.8 "Absolutly positioned, replaced elements"
+    // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-width>
+    // (block-style-comments in this function correspond to text from the spec and
+    // the numbers correspond to numbers in spec)
 
-        if (mt == AUTO && mb == AUTO) {
-            // both margins auto, solve for equality
-            mt = (ch - ot)/2;
-            mb = ch - ot - mt;
+    // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
+    const RenderObject* containerBlock = container();
+    const int containerWidth = containingBlockWidth() + containerBlock->paddingLeft() + containerBlock->paddingRight();
+
+    // Variables to solve.
+    Length left = style()->left();
+    Length right = style()->right();
+    Length marginLeft = style()->marginLeft();
+    Length marginRight = style()->marginRight();
+
+
+    /*-----------------------------------------------------------------------*\
+     * 1. The used value of 'width' is determined as for inline replaced
+     *    elements.
+    \*-----------------------------------------------------------------------*/
+    // NOTE: This value of width is FINAL in that the min/max width calculations
+    // are dealt with in calcReplacedWidth().  This means that the steps to produce
+    // correct max/min in the non-replaced version, are not necessary.
+    m_width = calcReplacedWidth() + borderLeft() + borderRight() + paddingLeft() + paddingRight();
+    const int availableSpace = containerWidth - m_width;
+
+    /*-----------------------------------------------------------------------*\
+     * 2. If both 'left' and 'right' have the value 'auto', then if 'direction'
+     *    of the containing block is 'ltr', set 'left' to the static position;
+     *    else if 'direction' is 'rtl', set 'right' to the static position.
+    \*-----------------------------------------------------------------------*/
+    // see FIXME 2
+    if (left.isAuto() && right.isAuto()) {
+        // see FIXME 1
+        if (containerBlock->style()->direction() == LTR) {
+            // 'm_staticX' should already have been set through layout of the parent.
+            int staticPosition = m_staticX - containerBlock->borderLeft();
+            for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent())
+                staticPosition += po->xPos();
+            left.setValue(Fixed, staticPosition);
+        } else {
+            RenderObject* po = parent();
+            // 'm_staticX' should already have been set through layout of the parent.
+            int staticPosition = m_staticX + containerWidth + containerBlock->borderRight() - po->width();
+            for (; po && po != containerBlock; po = po->parent())
+                staticPosition -= po->xPos();
+            right.setValue(Fixed, staticPosition);
         }
-        else if (mt==AUTO)
-            // solve for top margin
-            mt = ch - ot - mb;
-        else if (mb==AUTO)
-            // solve for bottom margin
-            mb = ch - ot - mt;
-        else
-            // overconstrained, solve for bottom
-            b = ch - (h + t + mt + mb + pab);
     }
-    else {
-        // one or two of (top, height, bottom) missing, solve
-
-        // auto margins are ignored
-        if (mt == AUTO)
-            mt = 0;
-        if (mb == AUTO)
-            mb = 0;
-
-        //1. solve top & height. use content height.
-        if (t == AUTO && h == AUTO && b != AUTO) {
-            h = ourHeight - pab;
-            t = ch - (h + b + mt + mb + pab);
-        }
-        else if (t == AUTO && h != AUTO && b == AUTO) //2. solve top & bottom. use static positioning.
-        {
-            t = static_top;
-            b = ch - (h + t + mt + mb + pab);
-        }
-        else if (t != AUTO && h == AUTO && b == AUTO) //3. solve height & bottom. use content height.
-        {
-            h = ourHeight - pab;
-            b = ch - (h + t + mt + mb + pab);
+
+    /*-----------------------------------------------------------------------*\
+     * 3. If 'left' or 'right' are 'auto', replace any 'auto' on 'margin-left'
+     *    or 'margin-right' with '0'.
+    \*-----------------------------------------------------------------------*/
+    if (left.isAuto() || right.isAuto()) {
+        if (marginLeft.isAuto())
+            marginLeft.setValue(Fixed, 0);
+        if (marginRight.isAuto())
+            marginRight.setValue(Fixed, 0);
+    }
+
+    /*-----------------------------------------------------------------------*\
+     * 4. If at this point both 'margin-left' and 'margin-right' are still
+     *    'auto', solve the equation under the extra constraint that the two
+     *    margins must get equal values, unless this would make them negative,
+     *    in which case when the direction of the containing block is 'ltr'
+     *    ('rtl'), set 'margin-left' ('margin-right') to zero and solve for
+     *    'margin-right' ('margin-left').
+    \*-----------------------------------------------------------------------*/
+    int leftValue;
+    int rightValue;
+
+    if (marginLeft.isAuto() && marginRight.isAuto()) {
+        // 'left' and 'right' cannot be 'auto' due to step 3
+        ASSERT(!(left.isAuto() && right.isAuto()));
+
+        leftValue = left.calcValue(containerWidth);
+        rightValue = right.calcValue(containerWidth);
+
+        int difference = availableSpace - (leftValue + rightValue);
+        if (difference > 0) {
+            m_marginLeft = difference / 2; // split the diference
+            m_marginRight = difference - m_marginLeft; // account for odd valued differences
+        } else {
+            // see FIXME 1
+            if (containerBlock->style()->direction() == LTR) {
+                m_marginLeft = 0;
+                m_marginRight = difference;  // will be negative
+            } else {
+                m_marginLeft = difference;  // will be negative
+                m_marginRight = 0;
+            }
         }
-        else
-        //4. solve top
-        if (t == AUTO && h != AUTO && b != AUTO)
-            t = ch - (h + b + mt + mb + pab);
-        else
 
-        //5. solve height
-        if (t != AUTO && h == AUTO && b != AUTO)
-            h = ch - (t + b + mt + mb + pab);
-        else
+    /*-----------------------------------------------------------------------*\
+     * 5. If at this point there is an 'auto' left, solve the equation for
+     *    that value.
+    \*-----------------------------------------------------------------------*/
+    } else if (left.isAuto()) {
+        m_marginLeft = marginLeft.calcValue(containerWidth);
+        m_marginRight = marginRight.calcValue(containerWidth);
+        rightValue = right.calcValue(containerWidth);
+
+        // Solve for 'left'
+        leftValue = availableSpace - (rightValue + m_marginLeft + m_marginRight);
+    } else if (right.isAuto()) {
+        m_marginLeft = marginLeft.calcValue(containerWidth);
+        m_marginRight = marginRight.calcValue(containerWidth);
+        leftValue = left.calcValue(containerWidth);
+
+        // Solve for 'right'
+        rightValue = availableSpace - (leftValue + m_marginLeft + m_marginRight);
+    } else if (marginLeft.isAuto()) {
+        m_marginRight = marginRight.calcValue(containerWidth);
+        leftValue = left.calcValue(containerWidth);
+        rightValue = right.calcValue(containerWidth);
+
+        // Solve for 'margin-left'
+        m_marginLeft = availableSpace - (leftValue + rightValue + m_marginRight);
+    } else if (marginRight.isAuto()) {
+        m_marginLeft = marginLeft.calcValue(containerWidth);
+        leftValue = left.calcValue(containerWidth);
+        rightValue = right.calcValue(containerWidth);
+
+        // Solve for 'margin-right'
+        m_marginRight = availableSpace - (leftValue + rightValue + m_marginLeft);
+    }
+
+    /*-----------------------------------------------------------------------*\
+     * 6. If at this point the values are over-constrained, ignore the value
+     *    for either 'left' (in case the 'direction' property of the
+     *    containing block is 'rtl') or 'right' (in case 'direction' is
+     *    'ltr') and solve for that value.
+    \*-----------------------------------------------------------------------*/
+    // NOTE:  It is not necessary to solve for 'right' when the direction is
+    // LTR because the value is not used.
+    int totalWidth = m_width + leftValue + rightValue +  m_marginLeft + m_marginRight;
+    // see FIXME 1
+    if (totalWidth > containerWidth && (containerBlock->style()->direction() == RTL))
+        leftValue = containerWidth - (totalWidth - leftValue);
+
+
+    // Use computed values to caluculate the horizontal position.
+    m_x = leftValue + m_marginLeft + containerBlock->borderLeft();
+}
 
-        //6. solve bottom
-        if (t != AUTO && h != AUTO && b == AUTO)
-            b = ch - (h + t + mt + mb + pab);
-    }
+void RenderBox::calcAbsoluteVerticalReplaced()
+{
+    // The following is based off of the W3C Working Draft from April 11, 2006 of
+    // CSS 2.1: Section 10.6.5 "Absolutly positioned, replaced elements"
+    // <http://www.w3.org/TR/2005/WD-CSS21-20050613/visudet.html#abs-replaced-height>
+    // (block-style-comments in this function correspond to text from the spec and
+    // the numbers correspond to numbers in spec)
 
-    if (ourHeight < h + pab) //content must still fit
-        ourHeight = h + pab;
+    // We don't use containingBlock(), since we may be positioned by an enclosing relpositioned inline.
+    const RenderObject* containerBlock = container();
+
+    // Even in strict mode (where we don't grow the root to fill the viewport)
+    // other browsers position as though the root fills the viewport.
+    const int containerHeight = containerBlock->isRoot() ? containerBlock->availableHeight() : (containerBlock->height() - containerBlock->borderTop() - containerBlock->borderBottom());
+
+    // Variables to solve.
+    Length top = style()->top();
+    Length bottom = style()->bottom();
+    Length marginTop = style()->marginTop();
+    Length marginBottom = style()->marginBottom();
+
+
+    /*-----------------------------------------------------------------------*\
+     * 1. The used value of 'height' is determined as for inline replaced
+     *    elements.
+    \*-----------------------------------------------------------------------*/
+    // NOTE: This value of height is FINAL in that the min/max height calculations
+    // are dealt with in calcReplacedHeight().  This means that the steps to produce
+    // correct max/min in the non-replaced version, are not necessary.
+    int heightValue = calcReplacedHeight() + borderTop() + borderBottom() + paddingTop() + paddingBottom();
+    int availableSpace = containerHeight - heightValue;
+
+    /*-----------------------------------------------------------------------*\
+     * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top'
+     *    with the element's static position.
+    \*-----------------------------------------------------------------------*/
+    // see FIXME 2
+    if (top.isAuto() && bottom.isAuto()) {
+        // m_staticY should already have been set through layout of the parent().
+        int staticTop = m_staticY - containerBlock->borderTop();
+        for (RenderObject* po = parent(); po && po != containerBlock; po = po->parent()) {
+            if (!po->isTableRow())
+                staticTop += po->yPos();
+        }
+        top.setValue(Fixed, staticTop);
+    }
+
+    /*-----------------------------------------------------------------------*\
+     * 3. If 'bottom' is 'auto', replace any 'auto' on 'margin-top' or
+     *    'margin-bottom' with '0'.
+    \*-----------------------------------------------------------------------*/
+    // FIXME: The spec. says that this step should only be taken when bottom is
+    // auto, but if only top is auto, this makes step 4 impossible.
+    if (top.isAuto() || bottom.isAuto()) {
+        if (marginTop.isAuto())
+            marginTop.setValue(Fixed, 0);
+        if (marginBottom.isAuto())
+            marginBottom.setValue(Fixed, 0);
+    }
+
+    /*-----------------------------------------------------------------------*\
+     * 4. If at this point both 'margin-top' and 'margin-bottom' are still
+     *    'auto', solve the equation under the extra constraint that the two
+     *    margins must get equal values.
+    \*-----------------------------------------------------------------------*/
+    int topValue;
+    int bottomValue;
+
+    if (marginTop.isAuto() && marginBottom.isAuto()) {
+        // 'top' and 'bottom' cannot be 'auto' due to step 2 and 3 combinded.
+        ASSERT(!(top.isAuto() && bottom.isAuto()));
+
+        topValue = top.calcValue(containerHeight);
+        bottomValue = bottom.calcValue(containerHeight);
+
+        int difference = availableSpace - (topValue + bottomValue);
+        // NOTE: This may result in negative values.
+        m_marginTop =  difference / 2; // split the difference
+        m_marginBottom = difference - m_marginTop; // account for odd valued differences
+
+    /*-----------------------------------------------------------------------*\
+     * 5. If at this point there is only one 'auto' left, solve the equation
+     *    for that value.
+    \*-----------------------------------------------------------------------*/
+    } else if (top.isAuto()) {
+        m_marginTop = marginTop.calcValue(containerHeight);
+        m_marginBottom = marginBottom.calcValue(containerHeight);
+        bottomValue = bottom.calcValue(containerHeight);
+
+        // Solve for 'top'
+        topValue = availableSpace - (bottomValue + m_marginTop + m_marginBottom);
+    } else if (bottom.isAuto()) {
+        m_marginTop = marginTop.calcValue(containerHeight);
+        m_marginBottom = marginBottom.calcValue(containerHeight);
+        topValue = top.calcValue(containerHeight);
+
+        // Solve for 'bottom'
+        // NOTE: It is not necessary to solve for 'bottom' because we don't ever
+        // use the value.
+    } else if (marginTop.isAuto()) {
+        m_marginBottom = marginBottom.calcValue(containerHeight);
+        topValue = top.calcValue(containerHeight);
+        bottomValue = bottom.calcValue(containerHeight);
+
+        // Solve for 'margin-top'
+        m_marginTop = availableSpace - (topValue + bottomValue + m_marginBottom);
+    } else if (marginBottom.isAuto()) {
+        m_marginTop = marginTop.calcValue(containerHeight);
+        topValue = top.calcValue(containerHeight);
+        bottomValue = bottom.calcValue(containerHeight);
+
+        // Solve for 'margin-bottom'
+        m_marginBottom = availableSpace - (topValue + bottomValue + m_marginTop);
+    }
+
+    /*-----------------------------------------------------------------------*\
+     * 6. If at this point the values are over-constrained, ignore the value
+     *    for 'bottom' and solve for that value.
+    \*-----------------------------------------------------------------------*/
+    // NOTE: It is not necessary to do this step because we don't end up using
+    // the value of 'bottom' regardless of whether the values are over-constrained
+    // or not.
+
+
+    // Make final adjustments to height.
+    int contentHeight = m_height;
+    if ((contentHeight < heightValue) || (hasOverflowClip() && contentHeight > heightValue))
+        contentHeight = heightValue;
+
+    // Do not allow the height to be negative.  This can happen when someone
+    // specifies both top and bottom but the containing block height is less
+    // than top, e.g., top: 20px, bottom: 0, containing block height 16.
+    heightValue = max(0, contentHeight);
+
+    // If our content height exceeds the new height once we've set it, then we
+    // need to make sure to update overflow to track the spillout.
+    if (m_height > heightValue)
+        setOverflowHeight(m_height);
 
-    if (hasOverflowClip() && ourHeight > h + pab)
-        ourHeight = h + pab;
-    
-    // Do not allow the height to be negative.  This can happen when someone specifies both top and bottom
-    // but the containing block height is less than top, e.g., top:20px, bottom:0, containing block height 16.
-    ourHeight = max(0, ourHeight);
-    
-    h = ourHeight;
-    y = t + mt + cb->borderTop();
+    // Set final values.
+    m_height = heightValue;
+
+    // Use computed values to caluculate the vertical position.
+    m_y = topValue + m_marginTop + containerBlock->borderTop();
 }
 
 IntRect RenderBox::caretRect(int offset, EAffinity affinity, int* extraWidthToEndOfLine)
index 8958a6dae96ded09e01ed4455bed60ef7afe1bed..b3a5648270b7449b8e3d1b94115dcfd3ee216fef 100644 (file)
@@ -158,11 +158,18 @@ protected:
 
     void calcAbsoluteHorizontal();
     void calcAbsoluteVertical();
-    void calcAbsoluteHorizontalValues(WidthType widthType, RenderObject* cb, int cw, int pab, int static_distance,
-                                      int l, int r, int& w, int& ml, int& mr, int& x);
-    void calcAbsoluteVerticalValues(HeightType heightType, RenderObject* cb, int ch, int pab, 
-                                    int t, int b, int& h, int& mt, int& mb, int& y); 
-    
+    void calcAbsoluteHorizontalValues(Length width, const RenderObject* cb, 
+                                      const int containerWidth, const int bordersPlusPadding, 
+                                      const Length left, const Length right, const Length marginLeft, const Length marginRight,
+                                      int& widthValue, int& marginLeftValue, int& marginRightValue, int& xPos);
+    void calcAbsoluteVerticalValues(Length height, const RenderObject* cb, 
+                                    const int containerHeight, const int bordersPlusPadding,
+                                    const Length top, const Length bottom, const Length marginTop, const Length marginBottom,
+                                    int& heightValue, int& marginTopValue, int& marginBottomValue, int& yPos);
+
+    void calcAbsoluteVerticalReplaced();
+    void calcAbsoluteHorizontalReplaced();
+
     virtual IntRect getOverflowClipRect(int tx, int ty);
     virtual IntRect getClipRect(int tx, int ty);