Reviewed by Dave Hyatt (rendering) and Maciej (editing).
authorharrison <harrison@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 30 Jun 2005 01:27:47 +0000 (01:27 +0000)
committerharrison <harrison@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 30 Jun 2005 01:27:47 +0000 (01:27 +0000)
        Test cases added:  Coming soon.  Will include with next round of changes for this bug.

        This is the first checkin for...

        <rdar://problem/3792529> REGRESSION (Mail): Tabs do not work the way they did in Panther (especially useful in plain text mail)

        Basic strategy is to put tabs into spans with white-space:pre style, and
        render them with tabs stops every 8th space, where the space width and
        the left margin are those of the enclosing block.

        What's left is to switch to implement white-space:pre-wrap so
        that we can coalesce consecutive tabs while maintaining proper
        line breaking.  That will keep the markup smaller.

        * khtml/editing/apply_style_command.cpp:
        (khtml::createStyleSpanElement):
        (khtml::ApplyStyleCommand::removeCSSStyle):
        (khtml::ApplyStyleCommand::addInlineStyleIfNeeded):
        * khtml/editing/delete_selection_command.cpp:
        (khtml::DeleteSelectionCommand::saveTypingStyleState):
        * khtml/editing/edit_command.cpp:
        (khtml::EditCommand::styleAtPosition):
        * khtml/editing/html_interchange.h:
        * khtml/editing/htmlediting.cpp:
        (khtml::isSpecialElement):
        (khtml::isTabSpanNode):
        (khtml::isTabSpanTextNode):
        (khtml::positionBeforeTabSpan):
        (khtml::createTabSpanElement):
        * khtml/editing/htmlediting.h:
        * khtml/editing/insert_text_command.cpp:
        (khtml::InsertTextCommand::prepareForTextInsertion):
        (khtml::InsertTextCommand::input):
        (khtml::InsertTextCommand::insertTab):
        * khtml/editing/insert_text_command.h:
        * khtml/editing/markup.cpp:
        (khtml::createParagraphContentsFromString):
        (khtml::createFragmentFromText):
        * khtml/editing/replace_selection_command.cpp:
        (khtml::ReplacementFragment::removeStyleNodes):
        * khtml/html/htmltokenizer.cpp:
        (khtml::HTMLTokenizer::begin):
        (khtml::HTMLTokenizer::processListing):
        (khtml::HTMLTokenizer::parseEntity):
        (khtml::HTMLTokenizer::parseTag):
        (khtml::HTMLTokenizer::addPending):
        (khtml::HTMLTokenizer::write):
        * khtml/html/htmltokenizer.h:
        (khtml::HTMLTokenizer::):
        * khtml/rendering/bidi.cpp:
        (khtml::addRun):
        (khtml::RenderBlock::tabWidth):
        (khtml::RenderBlock::computeHorizontalPositionsForLine):
        (khtml::RenderBlock::skipWhitespace):
        (khtml::RenderBlock::findNextLineBreak):
        (khtml::RenderBlock::checkLinesForTextOverflow):
        * khtml/rendering/break_lines.cpp:
        (khtml::isBreakable):
        * khtml/rendering/font.cpp:
        (Font::drawHighlightForText):
        (Font::drawText):
        (Font::floatWidth):
        (Font::floatCharacterWidths):
        (Font::checkSelectionPoint):
        (Font::width):
        * khtml/rendering/font.h:
        * khtml/rendering/render_block.cpp:
        (khtml::stripTrailingSpace):
        (khtml::RenderBlock::calcInlineMinMaxWidth):
        * khtml/rendering/render_block.h:
        * khtml/rendering/render_br.h:
        (khtml::RenderBR::width):
        * khtml/rendering/render_flexbox.cpp:
        (khtml::RenderFlexibleBox::layoutVerticalBox):
        * khtml/rendering/render_image.cpp:
        (RenderImage::setPixmap):
        (RenderImage::paint):
        * khtml/rendering/render_line.cpp:
        (khtml::EllipsisBox::paint):
        * khtml/rendering/render_line.h:
        (khtml::InlineBox::width):
        (khtml::InlineBox::xPos):
        (khtml::InlineBox::yPos):
        (khtml::InlineBox::height):
        (khtml::InlineBox::baseline):
        * khtml/rendering/render_list.cpp:
        (RenderListMarker::paint):
        (RenderListMarker::calcMinMaxWidth):
        * khtml/rendering/render_object.cpp:
        (RenderObject::tabWidth):
        (RenderObject::recalcMinMaxWidths):
        * khtml/rendering/render_object.h:
        * khtml/rendering/render_replaced.cpp:
        * khtml/rendering/render_text.cpp:
        (InlineTextBox::selectionRect):
        (InlineTextBox::paint):
        (InlineTextBox::paintSelection):
        (InlineTextBox::paintMarkedTextBackground):
        (InlineTextBox::textPos):
        (InlineTextBox::offsetForPosition):
        (InlineTextBox::positionForOffset):
        (RenderText::cacheWidths):
        (RenderText::widthFromCache):
        (RenderText::trimmedMinMaxWidth):
        (RenderText::calcMinMaxWidth):
        (RenderText::containsOnlyWhitespace):
        (RenderText::width):
        * khtml/rendering/render_text.h:
        * kwq/KWQFontMetrics.h:
        * kwq/KWQFontMetrics.mm:
        (QFontMetrics::width):
        (QFontMetrics::charWidth):
        (QFontMetrics::floatWidth):
        (QFontMetrics::floatCharacterWidths):
        (QFontMetrics::checkSelectionPoint):
        (QFontMetrics::boundingRect):
        (QFontMetrics::size):
        * kwq/KWQPainter.h:
        * kwq/KWQPainter.mm:
        (QPainter::drawText):
        (QPainter::drawHighlightForText):
        * kwq/WebCoreTextRenderer.h:
        * kwq/WebCoreTextRendererFactory.mm:
        (WebCoreInitializeEmptyTextStyle):
        * layout-tests/editing/deleting/delete-tab-001-expected.txt:
        * layout-tests/editing/deleting/delete-tab-001.html:
        * layout-tests/editing/deleting/delete-tab-002-expected.txt:
        * layout-tests/editing/deleting/delete-tab-002.html:
        * layout-tests/editing/deleting/delete-tab-003-expected.txt:
        * layout-tests/editing/deleting/delete-tab-003.html:
        * layout-tests/editing/deleting/delete-tab-004-expected.txt:
        * layout-tests/editing/deleting/delete-tab-004.html:
        * layout-tests/editing/inserting/insert-tab-001-expected.txt:
        * layout-tests/editing/inserting/insert-tab-002-expected.txt:
        * layout-tests/editing/inserting/insert-tab-003-expected.txt:
        * layout-tests/editing/inserting/insert-tab-004-expected.txt:
        * layout-tests/fast/dom/quadraticCurveTo-expected.txt:
        * layout-tests/fast/js/string-replace-2-expected.txt:
        * layout-tests/fast/table/039-expected.txt:
        * layout-tests/fast/table/border-collapsing/004-expected.txt:
        * layout-tests/fast/tokenizer/script_extra_close-expected.txt:

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

53 files changed:
LayoutTests/editing/deleting/delete-tab-001-expected.txt
LayoutTests/editing/deleting/delete-tab-001.html
LayoutTests/editing/deleting/delete-tab-002-expected.txt
LayoutTests/editing/deleting/delete-tab-002.html
LayoutTests/editing/deleting/delete-tab-003-expected.txt
LayoutTests/editing/deleting/delete-tab-003.html
LayoutTests/editing/deleting/delete-tab-004-expected.txt
LayoutTests/editing/deleting/delete-tab-004.html
LayoutTests/editing/inserting/insert-tab-001-expected.txt
LayoutTests/editing/inserting/insert-tab-002-expected.txt
LayoutTests/editing/inserting/insert-tab-003-expected.txt
LayoutTests/editing/inserting/insert-tab-004-expected.txt
LayoutTests/fast/dom/quadraticCurveTo-expected.txt
LayoutTests/fast/js/string-replace-2-expected.txt
LayoutTests/fast/table/039-expected.txt
LayoutTests/fast/table/border-collapsing/004-expected.txt
LayoutTests/fast/tokenizer/script_extra_close-expected.txt
WebCore/ChangeLog-2005-08-23
WebCore/khtml/editing/apply_style_command.cpp
WebCore/khtml/editing/delete_selection_command.cpp
WebCore/khtml/editing/edit_command.cpp
WebCore/khtml/editing/html_interchange.h
WebCore/khtml/editing/htmlediting.cpp
WebCore/khtml/editing/htmlediting.h
WebCore/khtml/editing/insert_text_command.cpp
WebCore/khtml/editing/insert_text_command.h
WebCore/khtml/editing/markup.cpp
WebCore/khtml/editing/replace_selection_command.cpp
WebCore/khtml/html/htmltokenizer.cpp
WebCore/khtml/html/htmltokenizer.h
WebCore/khtml/rendering/bidi.cpp
WebCore/khtml/rendering/break_lines.cpp
WebCore/khtml/rendering/font.cpp
WebCore/khtml/rendering/font.h
WebCore/khtml/rendering/render_block.cpp
WebCore/khtml/rendering/render_block.h
WebCore/khtml/rendering/render_br.h
WebCore/khtml/rendering/render_flexbox.cpp
WebCore/khtml/rendering/render_image.cpp
WebCore/khtml/rendering/render_line.cpp
WebCore/khtml/rendering/render_line.h
WebCore/khtml/rendering/render_list.cpp
WebCore/khtml/rendering/render_object.cpp
WebCore/khtml/rendering/render_object.h
WebCore/khtml/rendering/render_replaced.cpp
WebCore/khtml/rendering/render_text.cpp
WebCore/khtml/rendering/render_text.h
WebCore/kwq/KWQFontMetrics.h
WebCore/kwq/KWQFontMetrics.mm
WebCore/kwq/KWQPainter.h
WebCore/kwq/KWQPainter.mm
WebCore/kwq/WebCoreTextRenderer.h
WebCore/kwq/WebCoreTextRendererFactory.mm

index 87fd304e29ba50276d98b3acd09b761903bbdd0d..503a8076266eaf72cc7917595c15c5dabc3b3ce7 100644 (file)
@@ -4,8 +4,11 @@ layer at (0,0) size 800x600
   RenderBlock {HTML} at (0,0) size 800x600
     RenderBody {BODY} at (8,8) size 784x584
       RenderBlock {DIV} at (0,0) size 784x56 [border: (2px solid #FF0000)]
-        RenderInline {SPAN} at (0,0) size 56x28
-          RenderText {TEXT} at (14,14) size 56x28
-            text run at (14,14) width 56: "    foo"
+        RenderInline {SPAN} at (0,0) size 80x28
+          RenderInline {SPAN} at (0,0) size 48x28
+            RenderText {TEXT} at (14,14) size 48x28
+              text run at (14,14) width 48: "\x{9}"
+          RenderText {TEXT} at (62,14) size 32x28
+            text run at (62,14) width 32: "foo"
         RenderText {TEXT} at (0,0) size 0x0
-caret: position 4 of child 0 {TEXT} of child 1 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
+caret: position 1 of child 0 {TEXT} of child 0 {SPAN} of child 1 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
index b70368a8d8c292d6c465eafda1a9c8d1964173b2..c8068007feb2fbdca52c7fe0f7b48cea9998fd9d 100644 (file)
@@ -15,8 +15,7 @@
 function editingTest() {
     typeCharacterCommand('\t');
     typeCharacterCommand('\t');
-    for (i = 0; i < 4; i++)
-        deleteCommand();
+    deleteCommand();
 }
 
 </script>
index 42648253deb1615cdcd94098e000428b46eb229e..2fbf9a47a8d01e1a3a084434c86ee28a6e061732 100644 (file)
@@ -4,7 +4,10 @@ layer at (0,0) size 800x600
   RenderBlock {HTML} at (0,0) size 800x600
     RenderBody {BODY} at (8,8) size 784x584
       RenderBlock {DIV} at (0,0) size 784x56 [border: (2px solid #FF0000)]
-        RenderInline {SPAN} at (0,0) size 56x28
-          RenderText {TEXT} at (14,14) size 56x28
-            text run at (14,14) width 56: "foo    "
-caret: position 7 of child 0 {TEXT} of child 1 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
+        RenderInline {SPAN} at (0,0) size 48x28
+          RenderText {TEXT} at (14,14) size 32x28
+            text run at (14,14) width 32: "foo"
+          RenderInline {SPAN} at (0,0) size 16x28
+            RenderText {TEXT} at (46,14) size 16x28
+              text run at (46,14) width 16: "\x{9}"
+caret: position 1 of child 0 {TEXT} of child 1 {SPAN} of child 1 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
index c5720ef7e9e69648cb52079df84e84a3d0e775f7..4a3c0641c638846890e24b3f1dc7148758fee92f 100644 (file)
@@ -17,8 +17,7 @@ function editingTest() {
         moveSelectionForwardByCharacterCommand();
     typeCharacterCommand('\t');
     typeCharacterCommand('\t');
-    for (i = 0; i < 4; i++)
-        deleteCommand();
+    deleteCommand();
 }
 
 </script>
index bc7d6e4af1589ad325d24111e3349d42680d8064..7d4663106d2e23fe1843e2345bec4bcbc82ad3d2 100644 (file)
@@ -4,8 +4,13 @@ layer at (0,0) size 800x600
   RenderBlock {HTML} at (0,0) size 800x600
     RenderBody {BODY} at (8,8) size 784x584
       RenderBlock {DIV} at (0,0) size 784x56 [border: (2px solid #FF0000)]
-        RenderInline {SPAN} at (0,0) size 56x28
-          RenderText {TEXT} at (14,14) size 56x28
-            text run at (14,14) width 56: "fo    o"
+        RenderInline {SPAN} at (0,0) size 60x28
+          RenderText {TEXT} at (14,14) size 20x28
+            text run at (14,14) width 20: "fo"
+          RenderInline {SPAN} at (0,0) size 28x28
+            RenderText {TEXT} at (34,14) size 28x28
+              text run at (34,14) width 28: "\x{9}"
+          RenderText {TEXT} at (62,14) size 12x28
+            text run at (62,14) width 12: "o"
         RenderText {TEXT} at (0,0) size 0x0
-caret: position 6 of child 0 {TEXT} of child 1 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
+caret: position 1 of child 0 {TEXT} of child 1 {SPAN} of child 1 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
index fc40a5aef46456eb3eb075a69021ece336bd403d..9fe0f5789aa7383956df08f8eb321af4221ca382 100644 (file)
@@ -17,8 +17,7 @@ function editingTest() {
         moveSelectionForwardByCharacterCommand();
     typeCharacterCommand('\t');
     typeCharacterCommand('\t');
-    for (i = 0; i < 4; i++)
-        deleteCommand();
+    deleteCommand();
 }
 
 </script>
index 477cf06201135124db2987bf3e747fbb6d5b2da8..30bac16c2e1dad464a72a3e70073e3f3504cbda4 100644 (file)
@@ -4,9 +4,12 @@ layer at (0,0) size 800x600
   RenderBlock {HTML} at (0,0) size 800x600
     RenderBody {BODY} at (8,8) size 784x584
       RenderBlock {DIV} at (0,0) size 784x84 [border: (2px solid #FF0000)]
-        RenderInline {SPAN} at (0,0) size 56x56
+        RenderInline {SPAN} at (0,0) size 80x56
           RenderBR {BR} at (14,14) size 0x28
-          RenderText {TEXT} at (14,42) size 56x28
-            text run at (14,42) width 56: "    foo"
+          RenderInline {SPAN} at (0,0) size 48x28
+            RenderText {TEXT} at (14,42) size 48x28
+              text run at (14,42) width 48: "\x{9}"
+          RenderText {TEXT} at (62,42) size 32x28
+            text run at (62,42) width 32: "foo"
         RenderText {TEXT} at (0,0) size 0x0
-caret: position 4 of child 1 {TEXT} of child 1 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
+caret: position 1 of child 0 {TEXT} of child 1 {SPAN} of child 1 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
index 3e953241694eb01d977632435c240b83747073fd..88f1d2835548f675fdbee96ec80155807ce0626e 100644 (file)
@@ -16,8 +16,7 @@ function editingTest() {
     insertLineBreakCommand();
     typeCharacterCommand('\t');
     typeCharacterCommand('\t');
-    for (i = 0; i < 4; i++)
-        deleteCommand();
+    deleteCommand();
 }
 
 </script>
index 87fd304e29ba50276d98b3acd09b761903bbdd0d..503a8076266eaf72cc7917595c15c5dabc3b3ce7 100644 (file)
@@ -4,8 +4,11 @@ layer at (0,0) size 800x600
   RenderBlock {HTML} at (0,0) size 800x600
     RenderBody {BODY} at (8,8) size 784x584
       RenderBlock {DIV} at (0,0) size 784x56 [border: (2px solid #FF0000)]
-        RenderInline {SPAN} at (0,0) size 56x28
-          RenderText {TEXT} at (14,14) size 56x28
-            text run at (14,14) width 56: "    foo"
+        RenderInline {SPAN} at (0,0) size 80x28
+          RenderInline {SPAN} at (0,0) size 48x28
+            RenderText {TEXT} at (14,14) size 48x28
+              text run at (14,14) width 48: "\x{9}"
+          RenderText {TEXT} at (62,14) size 32x28
+            text run at (62,14) width 32: "foo"
         RenderText {TEXT} at (0,0) size 0x0
-caret: position 4 of child 0 {TEXT} of child 1 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
+caret: position 1 of child 0 {TEXT} of child 0 {SPAN} of child 1 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
index e1571e9ba7b02da5229cb4525d60092497c074d8..6d3c4f1d2855fc5d77062d4bf62eda3e9fa4b0a6 100644 (file)
@@ -4,8 +4,11 @@ layer at (0,0) size 800x600
   RenderBlock {HTML} at (0,0) size 800x600
     RenderBody {BODY} at (8,8) size 784x584
       RenderBlock {DIV} at (0,0) size 784x56 [border: (2px solid #FF0000)]
-        RenderInline {SPAN} at (0,0) size 56x28
-          RenderText {TEXT} at (14,14) size 56x28
-            text run at (14,14) width 56: "foo    "
+        RenderInline {SPAN} at (0,0) size 48x28
+          RenderText {TEXT} at (14,14) size 32x28
+            text run at (14,14) width 32: "foo"
+          RenderInline {SPAN} at (0,0) size 16x28
+            RenderText {TEXT} at (46,14) size 16x28
+              text run at (46,14) width 16: "\x{9}"
         RenderText {TEXT} at (0,0) size 0x0
-caret: position 7 of child 0 {TEXT} of child 1 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
+caret: position 1 of child 0 {TEXT} of child 1 {SPAN} of child 1 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
index bc7d6e4af1589ad325d24111e3349d42680d8064..7d4663106d2e23fe1843e2345bec4bcbc82ad3d2 100644 (file)
@@ -4,8 +4,13 @@ layer at (0,0) size 800x600
   RenderBlock {HTML} at (0,0) size 800x600
     RenderBody {BODY} at (8,8) size 784x584
       RenderBlock {DIV} at (0,0) size 784x56 [border: (2px solid #FF0000)]
-        RenderInline {SPAN} at (0,0) size 56x28
-          RenderText {TEXT} at (14,14) size 56x28
-            text run at (14,14) width 56: "fo    o"
+        RenderInline {SPAN} at (0,0) size 60x28
+          RenderText {TEXT} at (14,14) size 20x28
+            text run at (14,14) width 20: "fo"
+          RenderInline {SPAN} at (0,0) size 28x28
+            RenderText {TEXT} at (34,14) size 28x28
+              text run at (34,14) width 28: "\x{9}"
+          RenderText {TEXT} at (62,14) size 12x28
+            text run at (62,14) width 12: "o"
         RenderText {TEXT} at (0,0) size 0x0
-caret: position 6 of child 0 {TEXT} of child 1 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
+caret: position 1 of child 0 {TEXT} of child 1 {SPAN} of child 1 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
index 477cf06201135124db2987bf3e747fbb6d5b2da8..30bac16c2e1dad464a72a3e70073e3f3504cbda4 100644 (file)
@@ -4,9 +4,12 @@ layer at (0,0) size 800x600
   RenderBlock {HTML} at (0,0) size 800x600
     RenderBody {BODY} at (8,8) size 784x584
       RenderBlock {DIV} at (0,0) size 784x84 [border: (2px solid #FF0000)]
-        RenderInline {SPAN} at (0,0) size 56x56
+        RenderInline {SPAN} at (0,0) size 80x56
           RenderBR {BR} at (14,14) size 0x28
-          RenderText {TEXT} at (14,42) size 56x28
-            text run at (14,42) width 56: "    foo"
+          RenderInline {SPAN} at (0,0) size 48x28
+            RenderText {TEXT} at (14,42) size 48x28
+              text run at (14,42) width 48: "\x{9}"
+          RenderText {TEXT} at (62,42) size 32x28
+            text run at (62,42) width 32: "foo"
         RenderText {TEXT} at (0,0) size 0x0
-caret: position 4 of child 1 {TEXT} of child 1 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
+caret: position 1 of child 0 {TEXT} of child 1 {SPAN} of child 1 {SPAN} of child 1 {DIV} of child 1 {BODY} of child 0 {HTML} of document
index db8fa09b63f52efae98f9811286a20b652765566..d3bd5cd1a67f8f8b09d532570e85ccb35a499dff 100644 (file)
@@ -4,9 +4,8 @@ layer at (0,0) size 800x414
   RenderBlock {HTML} at (0,0) size 800x414
     RenderBody {BODY} at (8,16) size 784x18
       RenderBlock {P} at (0,0) size 784x18
-        RenderText {TEXT} at (0,0) size 420x18
-          text run at (0,0) width 358: "\x{9}\x{9}\x{9}This test case should produce a sine-wave stroked with 1"
-          text run at (358,0) width 62: "px black. "
-          text run at (420,0) width 0: "\x{9}\x{9}"
+        RenderText {TEXT} at (0,0) size 416x18
+          text run at (0,0) width 358: "This test case should produce a sine-wave stroked with 1"
+          text run at (358,0) width 58: "px black."
     RenderBlock (anonymous) at (0,50) size 800x364
       RenderCanvasImage {CANVAS} at (0,0) size 480x360
index 3968b0a4031a16d0f90ba53c8949f0df9cbdb8e4..f657389855f6c318b4e35a6765148c451b1c015a 100644 (file)
@@ -17,7 +17,7 @@ Your result: "-t's th- -nd -f th- w-rld -s w- kn-w -t, -nd - f--l f-n-."
 Support for String.replace(/…/,myFunction)
 
 function Capitalize(s){
-        return s.toUpperCase();
+       return s.toUpperCase();
 }
 result = foo.replace(vowels,Capitalize);
 Expected result: "It's thE End Of thE wOrld As wE knOw It, And I fEEl fInE."
@@ -26,7 +26,7 @@ Your result: "It's thE End Of thE wOrld As wE knOw It, And I fEEl fInE."
 Support for String.replace(/…/,myFunction), using RegExp
 
 function Capitalize(){
-        return RegExp.$1.toUpperCase()+RegExp.$2;
+       return RegExp.$1.toUpperCase()+RegExp.$2;
 }
 result = foo.replace(/([aeiou])([a-z])/g,Capitalize);
 Expected result: "It's the End Of the wOrld As we knOw It, And I fEel fIne."
@@ -35,7 +35,7 @@ Your result: "It's the End Of the wOrld As we knOw It, And I fEel fIne."
 Support for String.replace(/…/,myFunction), using parameters
 
 function Capitalize(orig,re1,re2){
-        return re1.toUpperCase()+re2;
+       return re1.toUpperCase()+re2;
 }
 result = foo.replace(/([aeiou])([a-z])/g,Capitalize);
 Expected result: "It's the End Of the wOrld As we knOw It, And I fEel fIne."
index 2b8a6bb18e22baa7aa1c84894dbaf993c961dfec..410d41cd288ae3826d3401a78894a75374ed7b08 100644 (file)
@@ -42,19 +42,11 @@ layer at (0,0) size 800x600
           RenderText {TEXT} at (0,0) size 49x18
             text run at (0,0) width 49: "Row 0:"
         RenderText {TEXT} at (49,0) size 170x18
-          text run at (49,0) width 38: " (1,1) "
-          text run at (87,0) width 34: "(1,2) "
-          text run at (121,0) width 34: "(1,3) "
-          text run at (155,0) width 34: "(1,4) "
-          text run at (189,0) width 30: "(1,5)"
+          text run at (49,0) width 170: " (1,1)\x{9}(1,2)\x{9}(1,3)\x{9}(1,4)\x{9}(1,5)"
         RenderBR {BR} at (0,0) size 0x0
         RenderInline {B} at (0,0) size 49x18
           RenderText {TEXT} at (0,18) size 49x18
             text run at (0,18) width 49: "Row 1:"
         RenderText {TEXT} at (49,18) size 170x18
-          text run at (49,18) width 38: " (2,1) "
-          text run at (87,18) width 34: "(2,2) "
-          text run at (121,18) width 34: "(2,3) "
-          text run at (155,18) width 34: "(2,4) "
-          text run at (189,18) width 30: "(2,5)"
+          text run at (49,18) width 170: " (2,1)\x{9}(2,2)\x{9}(2,3)\x{9}(2,4)\x{9}(2,5)"
         RenderBR {BR} at (0,0) size 0x0
index e1fefbf4748a9b474e7154214ac8750bf15b0351..17c9c521091f9cac873aa895f8e21d65bf9e86e9 100644 (file)
@@ -17,9 +17,9 @@ layer at (0,0) size 800x1438
           text run at (333,0) width 172: "The styles applied here are:"
       RenderBlock {PRE} at (0,92) size 784x180
         RenderText {TEXT} at (0,0) size 688x180
-          text run at (0,0) width 152: "TABLE   { margin: 1"
+          text run at (0,0) width 152: "TABLE\x{9}{ margin: 1"
           text run at (152,0) width 256: "em; border: medium solid blue; }"
-          text run at (0,15) width 368: "TD      { border: thin solid green; padding: 5"
+          text run at (0,15) width 368: "TD\x{9}{ border: thin solid green; padding: 5"
           text run at (368,15) width 40: "px; }"
           text run at (0,30) width 352: "TH { border: medium solid purple; padding: 5"
           text run at (352,30) width 40: "px; }"
@@ -34,7 +34,7 @@ layer at (0,0) size 800x1438
           text run at (0,120) width 328: "TABLE.five { border-collapse: separate; }"
           text run at (0,135) width 464: "TABLE.five, TABLE.five TD, TABLE.five TH { border: none; }"
           text run at (0,150) width 688: "TABLE.five TR, TABLE.five COL, TABLE.five COLGROUP, TABLE.five TBODY, TABLE.five THEAD"
-          text run at (0,165) width 296: "        { border: medium solid red; }"
+          text run at (0,165) width 296: "\x{9}{ border: medium solid red; }"
       RenderTable {TABLE} at (16,288) size 752x163
         RenderTableSection {TBODY} at (0,0) size 0x163
           RenderTableRow {TR} at (0,0) size 0x0
index cafc5c39fa99e62729bcb669bc499e7cb37538ea..3b09c3741caeb973fe1ee7743b693d8f1cbfabfe 100644 (file)
@@ -4,7 +4,7 @@ layer at (0,0) size 800x600
   RenderBlock {HTML} at (0,0) size 800x600
     RenderBody {BODY} at (8,8) size 784x584
       RenderText {TEXT} at (0,0) size 55x18
-        text run at (0,0) width 55: "TEST... "
+        text run at (0,0) width 55: "TEST...\x{9}"
       RenderText {TEXT} at (0,0) size 0x0
       RenderText {TEXT} at (0,0) size 0x0
       RenderText {TEXT} at (55,0) size 232x18
index f1a595f5ea7710b465694ead7746455d05fcf073..0b1e591e686fb50a62f26739ed4e1d4c25123b31 100644 (file)
@@ -1,3 +1,149 @@
+2005-06-29  David Harrison  <harrison@apple.com>
+
+        Reviewed by Dave Hyatt (rendering) and Maciej (editing).
+
+        Test cases added:  Coming soon.  Will include with next round of changes for this bug.
+
+        This is the first checkin for...
+        
+        <rdar://problem/3792529> REGRESSION (Mail): Tabs do not work the way they did in Panther (especially useful in plain text mail)
+        
+        Basic strategy is to put tabs into spans with white-space:pre style, and
+        render them with tabs stops every 8th space, where the space width and
+        the left margin are those of the enclosing block.
+        
+        What's left is to switch to implement white-space:pre-wrap so
+        that we can coalesce consecutive tabs while maintaining proper
+        line breaking.  That will keep the markup smaller.
+
+        * khtml/editing/apply_style_command.cpp:
+        (khtml::createStyleSpanElement):
+        (khtml::ApplyStyleCommand::removeCSSStyle):
+        (khtml::ApplyStyleCommand::addInlineStyleIfNeeded):
+        * khtml/editing/delete_selection_command.cpp:
+        (khtml::DeleteSelectionCommand::saveTypingStyleState):
+        * khtml/editing/edit_command.cpp:
+        (khtml::EditCommand::styleAtPosition):
+        * khtml/editing/html_interchange.h:
+        * khtml/editing/htmlediting.cpp:
+        (khtml::isSpecialElement):
+        (khtml::isTabSpanNode):
+        (khtml::isTabSpanTextNode):
+        (khtml::positionBeforeTabSpan):
+        (khtml::createTabSpanElement):
+        * khtml/editing/htmlediting.h:
+        * khtml/editing/insert_text_command.cpp:
+        (khtml::InsertTextCommand::prepareForTextInsertion):
+        (khtml::InsertTextCommand::input):
+        (khtml::InsertTextCommand::insertTab):
+        * khtml/editing/insert_text_command.h:
+        * khtml/editing/markup.cpp:
+        (khtml::createParagraphContentsFromString):
+        (khtml::createFragmentFromText):
+        * khtml/editing/replace_selection_command.cpp:
+        (khtml::ReplacementFragment::removeStyleNodes):
+        * khtml/html/htmltokenizer.cpp:
+        (khtml::HTMLTokenizer::begin):
+        (khtml::HTMLTokenizer::processListing):
+        (khtml::HTMLTokenizer::parseEntity):
+        (khtml::HTMLTokenizer::parseTag):
+        (khtml::HTMLTokenizer::addPending):
+        (khtml::HTMLTokenizer::write):
+        * khtml/html/htmltokenizer.h:
+        (khtml::HTMLTokenizer::):
+        * khtml/rendering/bidi.cpp:
+        (khtml::addRun):
+        (khtml::RenderBlock::tabWidth):
+        (khtml::RenderBlock::computeHorizontalPositionsForLine):
+        (khtml::RenderBlock::skipWhitespace):
+        (khtml::RenderBlock::findNextLineBreak):
+        (khtml::RenderBlock::checkLinesForTextOverflow):
+        * khtml/rendering/break_lines.cpp:
+        (khtml::isBreakable):
+        * khtml/rendering/font.cpp:
+        (Font::drawHighlightForText):
+        (Font::drawText):
+        (Font::floatWidth):
+        (Font::floatCharacterWidths):
+        (Font::checkSelectionPoint):
+        (Font::width):
+        * khtml/rendering/font.h:
+        * khtml/rendering/render_block.cpp:
+        (khtml::stripTrailingSpace):
+        (khtml::RenderBlock::calcInlineMinMaxWidth):
+        * khtml/rendering/render_block.h:
+        * khtml/rendering/render_br.h:
+        (khtml::RenderBR::width):
+        * khtml/rendering/render_flexbox.cpp:
+        (khtml::RenderFlexibleBox::layoutVerticalBox):
+        * khtml/rendering/render_image.cpp:
+        (RenderImage::setPixmap):
+        (RenderImage::paint):
+        * khtml/rendering/render_line.cpp:
+        (khtml::EllipsisBox::paint):
+        * khtml/rendering/render_line.h:
+        (khtml::InlineBox::width):
+        (khtml::InlineBox::xPos):
+        (khtml::InlineBox::yPos):
+        (khtml::InlineBox::height):
+        (khtml::InlineBox::baseline):
+        * khtml/rendering/render_list.cpp:
+        (RenderListMarker::paint):
+        (RenderListMarker::calcMinMaxWidth):
+        * khtml/rendering/render_object.cpp:
+        (RenderObject::tabWidth):
+        (RenderObject::recalcMinMaxWidths):
+        * khtml/rendering/render_object.h:
+        * khtml/rendering/render_replaced.cpp:
+        * khtml/rendering/render_text.cpp:
+        (InlineTextBox::selectionRect):
+        (InlineTextBox::paint):
+        (InlineTextBox::paintSelection):
+        (InlineTextBox::paintMarkedTextBackground):
+        (InlineTextBox::textPos):
+        (InlineTextBox::offsetForPosition):
+        (InlineTextBox::positionForOffset):
+        (RenderText::cacheWidths):
+        (RenderText::widthFromCache):
+        (RenderText::trimmedMinMaxWidth):
+        (RenderText::calcMinMaxWidth):
+        (RenderText::containsOnlyWhitespace):
+        (RenderText::width):
+        * khtml/rendering/render_text.h:
+        * kwq/KWQFontMetrics.h:
+        * kwq/KWQFontMetrics.mm:
+        (QFontMetrics::width):
+        (QFontMetrics::charWidth):
+        (QFontMetrics::floatWidth):
+        (QFontMetrics::floatCharacterWidths):
+        (QFontMetrics::checkSelectionPoint):
+        (QFontMetrics::boundingRect):
+        (QFontMetrics::size):
+        * kwq/KWQPainter.h:
+        * kwq/KWQPainter.mm:
+        (QPainter::drawText):
+        (QPainter::drawHighlightForText):
+        * kwq/WebCoreTextRenderer.h:
+        * kwq/WebCoreTextRendererFactory.mm:
+        (WebCoreInitializeEmptyTextStyle):
+        * layout-tests/editing/deleting/delete-tab-001-expected.txt:
+        * layout-tests/editing/deleting/delete-tab-001.html:
+        * layout-tests/editing/deleting/delete-tab-002-expected.txt:
+        * layout-tests/editing/deleting/delete-tab-002.html:
+        * layout-tests/editing/deleting/delete-tab-003-expected.txt:
+        * layout-tests/editing/deleting/delete-tab-003.html:
+        * layout-tests/editing/deleting/delete-tab-004-expected.txt:
+        * layout-tests/editing/deleting/delete-tab-004.html:
+        * layout-tests/editing/inserting/insert-tab-001-expected.txt:
+        * layout-tests/editing/inserting/insert-tab-002-expected.txt:
+        * layout-tests/editing/inserting/insert-tab-003-expected.txt:
+        * layout-tests/editing/inserting/insert-tab-004-expected.txt:
+        * layout-tests/fast/dom/quadraticCurveTo-expected.txt:
+        * layout-tests/fast/js/string-replace-2-expected.txt:
+        * layout-tests/fast/table/039-expected.txt:
+        * layout-tests/fast/table/border-collapsing/004-expected.txt:
+        * layout-tests/fast/tokenizer/script_extra_close-expected.txt:
+
 2005-06-29  Geoffrey Garen  <ggaren@apple.com>
 
        Contributed by Francisco Tolmasky <tolmasky@gmail.com>
index f91aa30ba88cb53978a77a7a3b1063b44affbe66..838a0f280c65a40e6cf150159ee381330b9ce4df 100644 (file)
@@ -32,6 +32,7 @@
 #include "css/cssparser.h"
 #include "css/cssproperties.h"
 #include "dom/dom_string.h"
+#include "htmlediting.h"
 #include "html/html_elementimpl.h"
 #include "misc/htmltags.h"
 #include "misc/htmlattrs.h"
@@ -284,7 +285,7 @@ static ElementImpl *createFontElement(DocumentImpl *document)
 ElementImpl *createStyleSpanElement(DocumentImpl *document)
 {
     int exceptionCode = 0;
-    ElementImpl *styleElement = document->createHTMLElement("SPAN", exceptionCode);
+    ElementImpl *styleElement = document->createHTMLElement("span", exceptionCode);
     ASSERT(exceptionCode == 0);
     styleElement->setAttribute(ATTR_CLASS, styleSpanClassString());
     return styleElement;
@@ -678,6 +679,8 @@ void ApplyStyleCommand::removeCSSStyle(CSSMutableStyleDeclarationImpl *style, HT
         int propertyID = (*it).id();
         CSSValueImpl *value = decl->getPropertyCSSValue(propertyID);
         if (value) {
+            if (propertyID == CSS_PROP_WHITE_SPACE && isTabSpanNode(elem))
+                continue;
             value->ref();
             removeCSSProperty(decl, propertyID);
             value->deref();
@@ -1248,6 +1251,10 @@ void ApplyStyleCommand::addInlineStyleIfNeeded(CSSMutableStyleDeclarationImpl *s
     StyleChange styleChange(style, Position(startNode, 0), StyleChange::styleModeForParseMode(document()->inCompatMode()));
     int exceptionCode = 0;
     
+    // Prevent style changes to our tab spans, because it might remove the whitespace:pre we are after
+    if (isTabSpanTextNode(startNode))
+        return;
+    
     //
     // Font tags need to go outside of CSS so that CSS font sizes override leagcy font sizes.
     //
index b8d2c76e4165aad1f9258acb1828e42f7dc395ad..1dbbe6e7a646268635c40f7793c0c3bbb0ca50e1 100644 (file)
@@ -267,7 +267,7 @@ void DeleteSelectionCommand::saveTypingStyleState()
     // Figure out the typing style in effect before the delete is done.
     // FIXME: Improve typing style.
     // See this bug: <rdar://problem/3769899> Implementation of typing style needs improvement
-    CSSComputedStyleDeclarationImpl *computedStyle = m_selectionToDelete.start().computedStyle();
+    CSSComputedStyleDeclarationImpl *computedStyle = positionBeforeTabSpan(m_selectionToDelete.start()).computedStyle();
     computedStyle->ref();
     m_typingStyle = computedStyle->copyInheritableProperties();
     m_typingStyle->ref();
index beaaef6ffe4f2d8b1e71ed05d7541cb01ce4c053..5874477b1d0efe31cc9b70c4f9dc9d263c8ba49c 100644 (file)
@@ -26,6 +26,7 @@
 #include "edit_command.h"
 #include "selection.h"
 #include "khtml_part.h"
+#include "htmlediting.h"
 
 #include "xml/dom_position.h"
 #include "xml/dom_docimpl.h"
@@ -389,7 +390,7 @@ bool EditCommand::isTypingCommand() const
 
 CSSMutableStyleDeclarationImpl *EditCommand::styleAtPosition(const Position &pos)
 {
-    CSSComputedStyleDeclarationImpl *computedStyle = pos.computedStyle();
+    CSSComputedStyleDeclarationImpl *computedStyle = positionBeforeTabSpan(pos).computedStyle();
     computedStyle->ref();
     CSSMutableStyleDeclarationImpl *style = computedStyle->copyInheritableProperties();
     computedStyle->deref();
index 24f6fb395f88d4faceb0fd9a118fe4ef8b81951f..85a4cb971c6b79ab18b8ac3053bfe501f5d18f7c 100644 (file)
@@ -32,6 +32,7 @@ class QString;
 #define AppleConvertedSpace       "Apple-converted-space"
 #define ApplePasteAsQuotation     "Apple-paste-as-quotation"
 #define AppleStyleSpanClass       "Apple-style-span"
+#define AppleTabSpanClass         "Apple-tab-span"
 
 enum EAnnotateForInterchange { DoNotAnnotateForInterchange, AnnotateForInterchange };
 
index 5159d135212556fd85e064e0fe6453eb75c895bd..e475712c3cce92e9f64c785c88fca36d041f4784 100644 (file)
@@ -126,8 +126,11 @@ static int maxRangeOffset(NodeImpl *n)
     return 1;
 }
 
-bool isSpecialElement(NodeImpl *n)
+bool isSpecialElement(const NodeImpl *n)
 {
+    if (!n)
+        return false;
+        
     if (!n->isHTMLElement())
         return false;
 
@@ -138,16 +141,18 @@ bool isSpecialElement(NodeImpl *n)
         return true;
 
     RenderObject *renderer = n->renderer();
-
-    if (renderer && (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE))
+    if (!renderer)
+        return false;
+        
+    if (renderer->style()->display() == TABLE || renderer->style()->display() == INLINE_TABLE)
         return true;
 
-    if (renderer && renderer->style()->isFloating())
+    if (renderer->style()->isFloating())
         return true;
 
-    if (renderer && renderer->style()->position() != STATIC)
+    if (renderer->style()->position() != STATIC)
         return true;
-
+        
     return false;
 }
 
@@ -280,6 +285,50 @@ ElementImpl *createBreakElement(DocumentImpl *document)
     return breakNode;
 }
 
+bool isTabSpanNode(const NodeImpl *node)
+{
+    return (node && node->isElementNode() && static_cast<const ElementImpl *>(node)->getAttribute("class") == AppleTabSpanClass);
+}
+
+bool isTabSpanTextNode(const NodeImpl *node)
+{
+    return (node && node->parentNode() && isTabSpanNode(node->parentNode()));
+}
+
+Position positionBeforeTabSpan(const Position& pos)
+{
+    NodeImpl *node = pos.node();
+    if (isTabSpanTextNode(node))
+        node = node->parent();
+    else if (!isTabSpanNode(node))
+        return pos;
+    
+    return Position(node->parentNode(), node->nodeIndex());
+}
+
+ElementImpl *createTabSpanElement(DocumentImpl *document, NodeImpl *tabTextNode)
+{
+    // make the span to hold the tab
+    int exceptionCode = 0;
+    ElementImpl *spanElement = document->createHTMLElement("span", exceptionCode);
+    assert(exceptionCode == 0);
+    spanElement->setAttribute(ATTR_CLASS, AppleTabSpanClass);
+    spanElement->setAttribute(ATTR_STYLE, "white-space:pre");
+
+    // add tab text to that span
+    if (!tabTextNode)
+        tabTextNode = document->createEditingTextNode("\t");
+    spanElement->appendChild(tabTextNode, exceptionCode);
+    assert(exceptionCode == 0);
+
+    return spanElement;
+}
+
+ElementImpl *createTabSpanElement(DocumentImpl *document, QString *tabText)
+{
+    return createTabSpanElement(document, document->createTextNode(*tabText));
+}
+
 bool isNodeRendered(const NodeImpl *node)
 {
     if (!node)
index daa7a4b345ec2a084267485465648f6cac4ce204..cd4b8c6e0ae0cc1b8731376f58c19735716fcff7 100644 (file)
@@ -58,15 +58,21 @@ void derefNodesInList(QPtrList<DOM::NodeImpl> &list);
 
 //------------------------------------------------------------------------------------------
 
+bool isSpecialElement(const DOM::NodeImpl *n);
+
 DOM::ElementImpl *createDefaultParagraphElement(DOM::DocumentImpl *document);
 DOM::ElementImpl *createBreakElement(DOM::DocumentImpl *document);
 
+bool isTabSpanNode(const DOM::NodeImpl *node);
+bool isTabSpanTextNode(const DOM::NodeImpl *node);
+DOM::Position positionBeforeTabSpan(const DOM::Position& pos);
+DOM::ElementImpl *createTabSpanElement(DOM::DocumentImpl *document, DOM::NodeImpl *tabTextNode=0);
+DOM::ElementImpl *createTabSpanElement(DOM::DocumentImpl *document, QString *tabText);
+
 bool isNodeRendered(const DOM::NodeImpl *);
 bool isMailBlockquote(const DOM::NodeImpl *);
 DOM::NodeImpl *nearestMailBlockquote(const DOM::NodeImpl *);
 
-bool isSpecialElement(DOM::NodeImpl *n);
-
 //------------------------------------------------------------------------------------------
 
 bool isTableStructureNode(const DOM::NodeImpl *node);
index cd78c563bd76343e0413c35062f3d9164925e4b4..f8b2d8e583bcce5cc16b2e7e5cb11b31f6d5c4c9 100644 (file)
 
 #include "khtml_part.h"
 #include "htmlediting.h"
+#include "html_interchange.h"
 #include "visible_position.h"
 #include "visible_text.h"
 #include "visible_units.h"
+#include "misc/htmlattrs.h"
 #include "xml/dom_docimpl.h"
 #include "xml/dom_position.h"
 #include "xml/dom_textimpl.h"
@@ -60,23 +62,10 @@ void InsertTextCommand::doApply()
 {
 }
 
-Position InsertTextCommand::prepareForTextInsertion(bool adjustDownstream)
+Position InsertTextCommand::prepareForTextInsertion(const Position& pos)
 {
-    // Prepare for text input by looking at the current position.
+    // Prepare for text input by looking at the specified position.
     // It may be necessary to insert a text node to receive characters.
-    Selection selection = endingSelection();
-    ASSERT(selection.isCaret());
-    
-    Position pos = selection.start();
-    if (adjustDownstream)
-        pos = pos.downstream();
-    else
-        pos = pos.upstream();
-    
-    Selection typingStyleRange;
-
-    pos = positionOutsideContainingSpecialElement(pos);
-
     if (!pos.node()->isTextNode()) {
         NodeImpl *textNode = document()->createEditingTextNode("");
         NodeImpl *nodeToInsert = textNode;
@@ -97,14 +86,30 @@ Position InsertTextCommand::prepareForTextInsertion(bool adjustDownstream)
         else
             ASSERT_NOT_REACHED();
         
-        pos = Position(textNode, 0);
+        return Position(textNode, 0);
     }
 
+#ifndef COALESCE_TAB_SPANS
+    ASSERT(!isTabSpanTextNode(pos.node()));
+#else
+    if (isTabSpanTextNode(pos.node())) {
+        NodeImpl *textNode = document()->createEditingTextNode("");
+        NodeImpl *originalTabSpan = pos.node()->parent();
+        if (pos.offset() <= pos.node()->caretMinOffset()) {
+            insertNodeBefore(textNode, originalTabSpan);
+        } else if (pos.offset() >= pos.node()->caretMaxOffset()) {
+            insertNodeAfter(textNode, originalTabSpan);
+        } else {
+            splitTextNodeContainingElement(static_cast<TextImpl *>(pos.node()), pos.offset());
+            insertNodeBefore(textNode, originalTabSpan);
+        }
+        return Position(textNode, 0);
+    }
+#endif
+
     return pos;
 }
 
-static const int spacesPerTab = 4;
-
 static inline bool isNBSP(const QChar &c)
 {
     return c.unicode() == 0xa0;
@@ -125,59 +130,51 @@ void InsertTextCommand::input(const DOMString &text, bool selectInsertedText)
     // out correctly after the insertion.
     selection = endingSelection();
     deleteInsignificantTextDownstream(selection.end().trailingWhitespacePosition(selection.endAffinity()));
-    
-    // Make sure the document is set up to receive text
-    Position startPosition = prepareForTextInsertion(adjustDownstream);
-    
-    Position endPosition;
-
-    TextImpl *textNode = static_cast<TextImpl *>(startPosition.node());
-    long offset = startPosition.offset();
 
-    // Now that we are about to add content, check to see if a placeholder element
-    // can be removed.
-    removeBlockPlaceholder(textNode->enclosingBlockFlowElement());
+    // Figure out the startPosition
+    Position startPosition = selection.start();
+    Position endPosition;
+    if (adjustDownstream)
+        startPosition = startPosition.downstream();
+    else
+        startPosition = startPosition.upstream();
+    startPosition = positionOutsideContainingSpecialElement(startPosition);
     
-    // These are temporary implementations for inserting adjoining spaces
-    // into a document. We are working on a CSS-related whitespace solution
-    // that will replace this some day. We hope.
     if (text == "\t") {
-        // Treat a tab like a number of spaces. This seems to be the HTML editing convention,
-        // although the number of spaces varies (we choose four spaces). 
-        // Note that there is no attempt to make this work like a real tab stop, it is merely 
-        // a set number of spaces. This also seems to be the HTML editing convention.
-        for (int i = 0; i < spacesPerTab; i++) {
+        endPosition = insertTab(startPosition);
+        startPosition = endPosition.previous();
+        removeBlockPlaceholder(startPosition.node()->enclosingBlockFlowElement());
+        m_charactersAdded += 1;
+    } else {
+        // Make sure the document is set up to receive text
+        startPosition = prepareForTextInsertion(startPosition);
+        removeBlockPlaceholder(startPosition.node()->enclosingBlockFlowElement());
+        TextImpl *textNode = static_cast<TextImpl *>(startPosition.node());
+        long offset = startPosition.offset();
+
+        if (text == " ") {
             insertSpace(textNode, offset);
+            endPosition = Position(textNode, offset + 1);
+
+            m_charactersAdded++;
             rebalanceWhitespace();
-            document()->updateLayout();
         }
-        
-        endPosition = Position(textNode, offset + spacesPerTab);
-
-        m_charactersAdded += spacesPerTab;
-    }
-    else if (text == " ") {
-        insertSpace(textNode, offset);
-        endPosition = Position(textNode, offset + 1);
-
-        m_charactersAdded++;
-        rebalanceWhitespace();
-    }
-    else {
-        const DOMString &existingText = textNode->data();
-        if (textNode->length() >= 2 && offset >= 2 && isNBSP(existingText[offset - 1]) && !isCollapsibleWhitespace(existingText[offset - 2])) {
-            // DOM looks like this:
-            // character nbsp caret
-            // As we are about to insert a non-whitespace character at the caret
-            // convert the nbsp to a regular space.
-            // EDIT FIXME: This needs to be improved some day to convert back only
-            // those nbsp's added by the editor to make rendering come out right.
-            replaceTextInNode(textNode, offset - 1, 1, " ");
+        else {
+            const DOMString &existingText = textNode->data();
+            if (textNode->length() >= 2 && offset >= 2 && isNBSP(existingText[offset - 1]) && !isCollapsibleWhitespace(existingText[offset - 2])) {
+                // DOM looks like this:
+                // character nbsp caret
+                // As we are about to insert a non-whitespace character at the caret
+                // convert the nbsp to a regular space.
+                // EDIT FIXME: This needs to be improved some day to convert back only
+                // those nbsp's added by the editor to make rendering come out right.
+                replaceTextInNode(textNode, offset - 1, 1, " ");
+            }
+            insertTextIntoNode(textNode, offset, text);
+            endPosition = Position(textNode, offset + text.length());
+
+            m_charactersAdded += text.length();
         }
-        insertTextIntoNode(textNode, offset, text);
-        endPosition = Position(textNode, offset + text.length());
-
-        m_charactersAdded += text.length();
     }
 
     setEndingSelection(Selection(startPosition, DOWNSTREAM, endPosition, SEL_DEFAULT_AFFINITY));
@@ -193,6 +190,54 @@ void InsertTextCommand::input(const DOMString &text, bool selectInsertedText)
         setEndingSelection(endingSelection().end(), endingSelection().endAffinity());
 }
 
+DOM::Position InsertTextCommand::insertTab(Position pos)
+{
+    Position insertPos = VisiblePosition(pos, DOWNSTREAM).deepEquivalent();
+    NodeImpl *node = insertPos.node();
+    unsigned int offset = insertPos.offset();
+
+#ifdef COALESCE_TAB_SPANS
+    // keep tabs coalesced in tab span
+    if (isTabSpanTextNode(node)) {
+        insertTextIntoNode(static_cast<TextImpl *>(node), offset, "\t");
+        return Position(node, offset + 1);
+    }
+#else
+    if (isTabSpanTextNode(node)) {
+        if (offset > (unsigned int) node->caretMinOffset())
+            insertPos = Position(node->parentNode(), node->nodeIndex() + 1);
+        else
+            insertPos = Position(node->parentNode(), node->nodeIndex());
+        node = insertPos.node();
+        offset = insertPos.offset();
+    }
+#endif
+    
+    // create new tab span
+    DOM::ElementImpl * spanNode = createTabSpanElement(document());
+    
+    // place it
+    if (!node->isTextNode()) {
+        insertNodeAt(spanNode, node, offset);
+    } else {
+        TextImpl *textNode = static_cast<TextImpl *>(node);
+        if (offset >= textNode->length()) {
+            insertNodeAfter(spanNode, textNode);
+        } else {
+            // split node to make room for the span
+            // NOTE: splitTextNode uses textNode for the
+            // second node in the split, so we need to
+            // insert the span before it.
+            if (offset > 0)
+                splitTextNode(textNode, offset);
+            insertNodeBefore(spanNode, textNode);
+        }
+    }
+    
+    // return the position following the new tab
+    return Position(spanNode->lastChild(), spanNode->lastChild()->caretMaxOffset());
+}
+
 void InsertTextCommand::insertSpace(TextImpl *textNode, unsigned long offset)
 {
     ASSERT(textNode);
index dcee4c324cf45be8c03b0286da62dd82a0ae897b..48cd7dc7c9e1ee5c30848a47fbff03ae753040c7 100644 (file)
@@ -45,8 +45,9 @@ public:
 private:
     virtual bool isInsertTextCommand() const;
 
-    DOM::Position prepareForTextInsertion(bool adjustDownstream);
+    DOM::Position prepareForTextInsertion(const DOM::Position& pos);
     void insertSpace(DOM::TextImpl *textNode, unsigned long offset);
+    DOM::Position insertTab(DOM::Position pos);
 
     unsigned long m_charactersAdded;
 };
index 7e6b248573d4ffd93e203357fbfb733f2b3c3349..e0b48d9b242c5749197b9fde5506ee52d56f3864 100644 (file)
@@ -485,6 +485,52 @@ QString createMarkup(const DOM::NodeImpl *node, EChildrenOnly includeChildren,
     return markup(node, includeChildren, false, nodes);
 }
 
+static void createParagraphContentsFromString(DOM::DocumentImpl *document, ElementImpl *paragraph, const QString &string)
+{
+    int exceptionCode = 0;
+    if (string.isEmpty()) {
+        NodeImpl *placeHolder = createBlockPlaceholderElement(document);
+        paragraph->appendChild(placeHolder, exceptionCode);
+        ASSERT(exceptionCode == 0);
+        return;
+    }
+
+    assert(string.find('\n') == -1);
+
+    QStringList tabList = QStringList::split('\t', string, true);
+    QString tabText = "";
+    while (!tabList.isEmpty()) {
+        QString s = tabList.first();
+        tabList.pop_front();
+
+        // append the non-tab textual part
+        if (!s.isEmpty()) {
+            if (tabText != "") {
+                paragraph->appendChild(createTabSpanElement(document, &tabText), exceptionCode);
+                ASSERT(exceptionCode == 0);
+                tabText = "";
+            }
+            NodeImpl *textNode = document->createTextNode(s);
+            paragraph->appendChild(textNode, exceptionCode);
+            ASSERT(exceptionCode == 0);
+        }
+
+        // there is a tab after every entry, except the last entry
+        // (if the last character is a tab, the list gets an extra empty entry)
+        if (!tabList.isEmpty()) {
+#ifdef COALESCE_TAB_SPANS
+            tabText += '\t';
+#else
+            paragraph->appendChild(createTabSpanElement(document), exceptionCode);
+            ASSERT(exceptionCode == 0);
+#endif
+        } else if (tabText != "") {
+            paragraph->appendChild(createTabSpanElement(document, &tabText), exceptionCode);
+            ASSERT(exceptionCode == 0);
+        }
+    }
+}
+
 DOM::DocumentFragmentImpl *createFragmentFromText(DOM::DocumentImpl *document, const QString &text)
 {
     if (!document)
@@ -496,10 +542,6 @@ DOM::DocumentFragmentImpl *createFragmentFromText(DOM::DocumentImpl *document, c
     if (!text.isEmpty()) {
         QString string = text;
 
-        // Replace tabs with four plain spaces.
-        // These spaces will get converted along with the other existing spaces below.
-        string.replace('\t', "    ");
-
         // FIXME: Wrap the NBSP's in a span that says "converted space".
         int offset = 0;
         int stringLength = string.length();
@@ -545,16 +587,8 @@ DOM::DocumentFragmentImpl *createFragmentFromText(DOM::DocumentImpl *document, c
                 element->setAttribute(ATTR_CLASS, AppleInterchangeNewline);            
             } else {
                 element = createDefaultParagraphElement(document);
-                NodeImpl *paragraphContents;
-                if (s.isEmpty()) {
-                    paragraphContents = createBlockPlaceholderElement(document);
-                } else {
-                    paragraphContents = document->createTextNode(s);
-                    ASSERT(exceptionCode == 0);
-                }
+                createParagraphContentsFromString(document, element, s);
                 element->ref();
-                element->appendChild(paragraphContents, exceptionCode);
-                ASSERT(exceptionCode == 0);
             }
             fragment->appendChild(element, exceptionCode);
             ASSERT(exceptionCode == 0);
index 9392da403bd531def02e119355d51b5b0f45c370..d79354adb047b24aa8d1d84b29a6c44244ea4445 100644 (file)
@@ -500,7 +500,7 @@ int ReplacementFragment::countRenderedBlocks(NodeImpl *holder)
 void ReplacementFragment::removeStyleNodes()
 {
     // Since style information has been computed and cached away in
-    // computeStylesForNodes(), these style nodes can be removed, since
+    // computeStylesUsingTestRendering(), these style nodes can be removed, since
     // the correct styles will be added back in fixupNodeStyles().
     NodeImpl *node = m_fragment->firstChild();
     while (node) {
@@ -522,7 +522,9 @@ void ReplacementFragment::removeStyleNodes()
             isStyleSpan(node)) {
             removeNodePreservingChildren(node);
         }
-        else if (node->isHTMLElement()) {
+        // need to skip tab span because fixupNodeStyles() is not called
+        // when replace is matching style
+        else if (node->isHTMLElement() && !isTabSpanNode(node)) {
             HTMLElementImpl *elem = static_cast<HTMLElementImpl *>(node);
             CSSMutableStyleDeclarationImpl *inlineStyleDecl = elem->inlineStyleDecl();
             if (inlineStyleDecl) {
index 80b8b53bbf3454053a8a36b4c0116903c5630070..5121c244e793ec4ccffa366ace3829552cac83e2 100644 (file)
@@ -311,8 +311,6 @@ void HTMLTokenizer::begin()
     tag = NoTag;
     pending = NonePending;
     discard = NoneDiscard;
-    pre = false;
-    prePos = 0;
     plaintext = false;
     xmp = false;
     processingInstruction = false;
@@ -349,16 +347,11 @@ void HTMLTokenizer::setForceSynchronous(bool force)
 
 void HTMLTokenizer::processListing(TokenizerString list)
 {
-    bool old_pre = pre;
     // This function adds the listing 'list' as
     // preformatted text-tokens to the token-collection
-    // thereby converting TABs.
-    if(!style) pre = true;
-    prePos = 0;
-
     while ( !list.isEmpty() )
     {
-        checkBuffer(3*TAB_SIZE);
+        checkBuffer();
 
         if (skipLF && ( *list != '\n' ))
         {
@@ -391,14 +384,11 @@ void HTMLTokenizer::processListing(TokenizerString list)
             }
             ++list;
         }
-        else if (( *list == ' ' ) || ( *list == '\t'))
+        else if ( *list == ' ' )
         {
             if (pending)
                 addPending();
-            if (*list == ' ')
-                pending = SpacePending;
-            else
-                pending = TabPending;
+            pending = SpacePending;
 
             ++list;
         }
@@ -408,7 +398,6 @@ void HTMLTokenizer::processListing(TokenizerString list)
             if (pending)
                 addPending();
 
-            prePos++;
             *dest++ = *list;
             ++list;
         }
@@ -417,10 +406,6 @@ void HTMLTokenizer::processListing(TokenizerString list)
 
     if (pending)
         addPending();
-
-    prePos = 0;
-
-    pre = old_pre;
 }
 
 void HTMLTokenizer::parseSpecial(TokenizerString &src)
@@ -941,8 +926,6 @@ void HTMLTokenizer::parseEntity(TokenizerString &src, QChar *&dest, bool start)
                 for(unsigned int i = 0; i < cBufferPos; i++)
                     dest[i] = cBuffer[i];
                 dest += cBufferPos;
-                if (pre)
-                    prePos += cBufferPos+1;
             }
 
             Entity = NoEntity;
@@ -1414,17 +1397,8 @@ void HTMLTokenizer::parseTag(TokenizerString &src)
 
             processToken();
 
-            // we have to take care to close the pre block in
-            // case we encounter an unallowed element....
-            if(pre && beginTag && !DOM::checkChild(ID_PRE, tagID, !parser->doc()->inCompatMode())) {
-                kdDebug(6036) << " not allowed in <pre> " << (int)tagID << endl;
-                pre = false;
-            }
-
             switch( tagID ) {
             case ID_PRE:
-                prePos = 0;
-                pre = beginTag;
                 discard = LFDiscard; // Discard the first LF after we open a pre.
                 break;
             case ID_SCRIPT:
@@ -1495,40 +1469,24 @@ void HTMLTokenizer::addPending()
     else if ( textarea || script )
     {
         switch(pending) {
-        case LFPending:  *dest++ = '\n'; prePos = 0; break;
-        case SpacePending: *dest++ = ' '; ++prePos; break;
-        case TabPending: *dest++ = '\t'; prePos += TAB_SIZE - (prePos % TAB_SIZE); break;
+        case LFPending:  *dest++ = '\n'; break;
+        case SpacePending: *dest++ = ' '; break;
         case NonePending:
             assert(0);
         }
     }
     else
     {
-        int p;
-
         switch (pending)
         {
         case SpacePending:
             // Insert a breaking space
             *dest++ = QChar(' ');
-            prePos++;
             break;
 
         case LFPending:
             *dest = '\n';
             dest++;
-            prePos = 0;
-            break;
-
-        case TabPending:
-            p = TAB_SIZE - ( prePos % TAB_SIZE );
-#ifdef TOKEN_DEBUG
-            qDebug("tab pending, prePos: %d, toadd: %d", prePos, p);
-#endif
-
-            for ( int x = 0; x < p; x++ )
-                *dest++ = QChar(' ');
-            prePos += p;
             break;
 
         case NonePending:
@@ -1683,9 +1641,7 @@ void HTMLTokenizer::write(const TokenizerString &str, bool appendData)
             }; // end case
 
             if ( pending ) {
-                // pre context always gets its spaces/linefeeds
-                if ( pre || script || (!parser->selectMode() &&
-                             (!parser->noSpaces() || dest > buffer )))
+                if ( script || (!parser->selectMode() && (!parser->noSpaces() || dest > buffer )))
                     addPending();
                 // just forget it
                 else
@@ -1755,7 +1711,7 @@ void HTMLTokenizer::write(const TokenizerString &str, bool appendData)
             }
             ++src;
         }
-        else if (( cc == ' ' ) || ( cc == '\t' ))
+        else if (cc == ' ')
         {
            if (select && !script) {
                 if(discard == SpaceDiscard)
@@ -1772,10 +1728,7 @@ void HTMLTokenizer::write(const TokenizerString &str, bool appendData)
             
                 if (pending)
                     addPending();
-                if (cc == ' ')
-                    pending = SpacePending;
-                else
-                    pending = TabPending;
+                pending = SpacePending;
             }
             
             ++src;
@@ -1786,10 +1739,6 @@ void HTMLTokenizer::write(const TokenizerString &str, bool appendData)
                 addPending();
 
             discard = NoneDiscard;
-            if ( pre )
-            {
-                prePos++;
-            }
 #if QT_VERSION < 300
             unsigned char row = src->row();
             if ( row > 0x05 && row < 0x10 || row > 0xfd )
index ac41a98dd4fc56d509dd382c4f468f15c626e8f8..3a2fc02f83a2d759b6a6cdd83205d3a6013a17f4 100644 (file)
@@ -116,9 +116,6 @@ public:
     bool flat;
 };
 
-// The count of spaces used for each tab.
-#define TAB_SIZE 8
-
 //-----------------------------------------------------------------------------
 
 class HTMLTokenizer : public Tokenizer, public CachedObjectClient
@@ -207,7 +204,6 @@ protected:
         NonePending = 0,
         SpacePending,
         LFPending,
-        TabPending
     } pending;
 
     // Discard line breaks immediately after start-tags
@@ -255,12 +251,6 @@ protected:
     // are we in a <script> ... </script block
     bool script;
 
-    // Are we in a <pre> ... </pre> block
-    bool pre;
-
-    // if 'pre == true' we track in which column we are
-    int prePos;
-
     // Are we in a <style> ... </style> block
     bool style;
 
index acb22035615f84c59161bf69cb6e180f4c126f63..24d8f25a80a65c16819725a2503047bf34d14b85 100644 (file)
@@ -386,7 +386,7 @@ static void addRun(BidiRun* bidiRun)
         if (text->text()) {
             for (int i = bidiRun->start; i < bidiRun->stop; i++) {
                 const QChar c = text->text()[i];
-                if (c == ' ' || c == '\n')
+                if (c == ' ' || c == '\n' || c == '\t')
                     numSpaces++;
             }
         }
@@ -714,6 +714,20 @@ RootInlineBox* RenderBlock::constructLine(const BidiIterator &start, const BidiI
     return lastRootBox();
 }
 
+// usage: tw - (xpos % tw);
+int RenderBlock::tabWidth(bool isWhitespacePre)
+{
+    if (!isWhitespacePre)
+        return 0;
+    
+    QChar   spaceChar(' ');
+    const Font& font = style()->htmlFont();
+    int tw = font.width(&spaceChar, 1, 0, 0);
+    tw *= 8;
+        
+    return tw;
+}
+
 void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, BidiState &bidi)
 {
     // First determine our total width.
@@ -725,7 +739,7 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, Bidi
             continue; // Positioned objects are only participating to figure out their
                       // correct static x position.  They have no effect on the width.
         if (r->obj->isText()) {
-            int textWidth = static_cast<RenderText *>(r->obj)->width(r->start, r->stop-r->start, m_firstLine);
+            int textWidth = static_cast<RenderText *>(r->obj)->width(r->start, r->stop-r->start, totWidth, m_firstLine);
             if (!r->compact) {
                 RenderStyle *style = r->obj->style();
                 if (style->whiteSpace() == NORMAL && style->khtmlLineBreak() == AFTER_WHITE_SPACE) {
@@ -797,7 +811,7 @@ void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, Bidi
                 int spaces = 0;
                 for ( int i = r->start; i < r->stop; i++ ) {
                     const QChar c = static_cast<RenderText *>(r->obj)->text()[i];
-                    if (c == ' ' || c == '\n')
+                    if (c == ' ' || c == '\n' || c == '\t')
                         spaces++;
                 }
 
@@ -1776,7 +1790,7 @@ int RenderBlock::skipWhitespace(BidiIterator &it, BidiState &bidi)
     // object iteration process.
     int w = lineWidth(m_height);
     while (!it.atEnd() && (it.obj->isInlineFlow() || (it.obj->style()->whiteSpace() != PRE && !it.obj->isBR() &&
-          (it.current() == ' ' || it.current() == '\n' || 
+          (it.current() == ' ' || it.current() == '\t' || it.current() == '\n' || 
            skipNonBreakingSpace(it) || it.obj->isFloatingOrPositioned())))) {
         if (it.obj->isFloatingOrPositioned()) {
             RenderObject *o = it.obj;
@@ -1986,12 +2000,12 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi
                 // item, then this is all moot. -dwh
                 RenderObject* next = Bidinext( start.par, o, bidi );
                 if (!m_pre && next && next->isText() && static_cast<RenderText*>(next)->stringLength() > 0) {
-                    if (static_cast<RenderText*>(next)->text()[0].unicode() == nonBreakingSpace &&
-                        o->style()->whiteSpace() == NORMAL && o->style()->nbspMode() == SPACE) {
-                        currentCharacterIsWS = true;
-                    }
-                    if (static_cast<RenderText*>(next)->text()[0].unicode() == ' ' ||
-                        static_cast<RenderText*>(next)->text()[0] == '\n') {
+                    RenderText *nextText = static_cast<RenderText*>(next);
+                    QChar nextChar = nextText->text()[0];
+
+                    if (nextText->style()->whiteSpace() != PRE && 
+                        (nextChar == ' ' || nextChar == '\n' || nextChar == '\t' ||
+                        nextChar.unicode() == nonBreakingSpace && next->style()->nbspMode() == SPACE)) {
                         currentCharacterIsSpace = true;
                         currentCharacterIsWS = true;
                         ignoringSpaces = true;
@@ -2022,7 +2036,7 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi
                 bool previousCharacterIsSpace = currentCharacterIsSpace;
                 bool previousCharacterIsWS = currentCharacterIsWS;
                 const QChar c = str[pos];
-                currentCharacterIsSpace = c == ' ' || (!isPre && c == '\n');
+                currentCharacterIsSpace = c == ' ' || (!isPre && (c == '\n' || c == '\t'));
                 
                 if (isPre || !currentCharacterIsSpace)
                     isLineEmpty = false;
@@ -2035,12 +2049,12 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi
                         addMidpoint(endMid);
                         
                         // Add the width up to but not including the hyphen.
-                        tmpW += t->width(lastSpace, pos - lastSpace, f);
+                        tmpW += t->width(lastSpace, pos - lastSpace, f, w+tmpW);
                         
                         // For whitespace normal only, include the hyphen.  We need to ensure it will fit
                         // on the line if it shows when we break.
                         if (o->style()->whiteSpace() == NORMAL)
-                            tmpW += t->width(pos, 1, f);
+                            tmpW += t->width(pos, 1, f, w+tmpW);
                         
                         BidiIterator startMid(0, o, pos+1);
                         addMidpoint(startMid);
@@ -2060,8 +2074,8 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi
                 currentCharacterIsWS = currentCharacterIsSpace || (breakNBSP && c.unicode() == nonBreakingSpace);
 
                 if (breakWords)
-                    wrapW += t->width(pos, 1, f);
-                if ((isPre && c == '\n') || (!isPre && isBreakable(str, pos, strlen, breakNBSP)) || (breakWords && wrapW > width)) {
+                    wrapW += t->width(pos, 1, f, w+wrapW);
+                if (c == '\n' || (!isPre && isBreakable(str, pos, strlen, breakNBSP)) || (breakWords && wrapW > width)) {
                     if (ignoringSpaces) {
                         if (!currentCharacterIsSpace) {
                             // Stop ignoring spaces and begin at this
@@ -2078,7 +2092,7 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi
                         }
                     }
 
-                    tmpW += t->width(lastSpace, pos - lastSpace, f);
+                    tmpW += t->width(lastSpace, pos - lastSpace, f, w+tmpW);
                     if (!appliedStartWidth) {
                         tmpW += inlineWidth(o, true, false);
                         appliedStartWidth = true;
@@ -2114,7 +2128,7 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi
                     if (o->style()->whiteSpace() == NORMAL) {
                         // In AFTER_WHITE_SPACE mode, consider the current character
                         // as candidate width for this line.
-                        int charWidth = o->style()->khtmlLineBreak() == AFTER_WHITE_SPACE ? t->width(pos, 1, f) : 0;
+                        int charWidth = o->style()->khtmlLineBreak() == AFTER_WHITE_SPACE ? t->width(pos, 1, f, w+tmpW) : 0;
                         if (w + tmpW + charWidth > width) {
                             if (o->style()->khtmlLineBreak() == AFTER_WHITE_SPACE) {
                                 // Check if line is too big even without the extra space
@@ -2132,7 +2146,7 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi
                         }
                         else if (pos > 1 && str[pos-1].unicode() == SOFT_HYPHEN)
                             // Subtract the width of the soft hyphen out since we fit on a line.
-                            tmpW -= t->width(pos-1, 1, f);
+                            tmpW -= t->width(pos-1, 1, f, w+tmpW);
                     }
 
                     if( *(str+pos) == '\n' && isPre) {
@@ -2204,7 +2218,7 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi
             
             // IMPORTANT: pos is > length here!
             if (!ignoringSpaces)
-                tmpW += t->width(lastSpace, pos - lastSpace, f);
+                tmpW += t->width(lastSpace, pos - lastSpace, f, w+tmpW);
             if (!appliedStartWidth)
                 tmpW += inlineWidth(o, true, false);
             if (!appliedEndWidth)
@@ -2408,8 +2422,8 @@ void RenderBlock::checkLinesForTextOverflow()
     static AtomicString ellipsisStr(ellipsis);
     const Font& firstLineFont = style(true)->htmlFont();
     const Font& font = style()->htmlFont();
-    int firstLineEllipsisWidth = firstLineFont.width(&ellipsis, 1, 0);
-    int ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(&ellipsis, 1, 0);
+    int firstLineEllipsisWidth = firstLineFont.width(&ellipsis, 1, 0, 0);
+    int ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(&ellipsis, 1, 0, 0);
 
     // For LTR text truncation, we want to get the right edge of our padding box, and then we want to see
     // if the right edge of a line box exceeds that.  For RTL, we use the left edge of the padding box and
index ef8df0f01c029be1a9deaf1f2dd7f064952a93c3..a3822bd9e34d57ffb9cdf8595f4ca7e24eac994c 100644 (file)
@@ -73,7 +73,7 @@ bool isBreakable(const QChar *s, int pos, int len, bool breakNBSP)
        else // no asian font
            return c->isSpace();
     } else {
-       if ( ch == ' ' || ch == '\n' )
+       if ( ch == ' ' || ch == '\t' || ch == '\n' )
            return true;
     }
     return false;
@@ -89,7 +89,7 @@ bool isBreakable(const QChar *s, int pos, int len, bool breakNBSP)
     // at the moment whether this behavior is correct or not.  Since Tiger is also not allowing breaks on spaces
     // after hyphen-like characters, this does not seem ideal for the Web.  Therefore for now we override space
     // characters up front and bypass the Unicode line breaking routines.
-    if (ch == '\n' || ch == ' ' || (breakNBSP && ch == 0xa0))
+    if (ch == ' ' || ch == '\n' || ch == '\t' || (breakNBSP && ch == 0xa0))
         return true;
 
     // If current character, or the previous character aren't simple latin1 then
index f910777e9ecaf01d7053e0abd155a031de5bfff2..8ade73fba9011008e1c94a12a4b67bdc41ba2805 100644 (file)
 using namespace khtml;
 
 #if APPLE_CHANGES
-void Font::drawHighlightForText( QPainter *p, int x, int y, int h, 
+void Font::drawHighlightForText( QPainter *p, int x, int y, int h, int tabWidth, int xpos, 
                      QChar *str, int slen, int pos, int len,
                      int toAdd, QPainter::TextDirection d, bool visuallyOrdered, int from, int to, QColor bg) const
 {
-    p->drawHighlightForText(x, y, h, str + pos, std::min(slen - pos, len), from, to, toAdd, bg, d, visuallyOrdered,
+    p->drawHighlightForText(x, y, h, tabWidth, xpos, str + pos, std::min(slen - pos, len), from, to, toAdd, bg, d, visuallyOrdered,
                 letterSpacing, wordSpacing, fontDef.smallCaps);
 }
 #endif
                      
-void Font::drawText( QPainter *p, int x, int y, QChar *str, int slen, int pos, int len,
+void Font::drawText( QPainter *p, int x, int y, int tabWidth, int xpos, QChar *str, int slen, int pos, int len,
                      int toAdd, QPainter::TextDirection d, bool visuallyOrdered, int from, int to, QColor bg ) const
 {
 #if APPLE_CHANGES
-    p->drawText(x, y, str + pos, std::min(slen - pos, len), from, to, toAdd, bg, d, visuallyOrdered,
+    p->drawText(x, y, tabWidth, xpos, str + pos, std::min(slen - pos, len), from, to, toAdd, bg, d, visuallyOrdered,
                 letterSpacing, wordSpacing, fontDef.smallCaps);
 #else
     QString qstr = QConstString(str, slen).string();
@@ -72,7 +72,7 @@ void Font::drawText( QPainter *p, int x, int y, QChar *str, int slen, int pos, i
     // ### fixme for RTL
     if ( !letterSpacing && !wordSpacing && !toAdd && from==-1 ) {
         // simply draw it
-        p->drawText( x, y, qstr, pos, len, d );
+        p->drawText( x, y, tabWidth, xpos, qstr, pos, len, d );
     } else {
         int numSpaces = 0;
         if ( toAdd ) {
@@ -104,7 +104,7 @@ void Font::drawText( QPainter *p, int x, int y, QChar *str, int slen, int pos, i
                 if ( bg.isValid() )
                     p->fillRect( x, y-fm.ascent(), chw, fm.height(), bg );
 
-                p->drawText( x, y, qstr, pos+i, 1, d );
+                p->drawText( x, y, tabWidth, xpos, qstr, pos+i, 1, d );
             }
             if ( d != QPainter::RTL )
                 x += chw;
@@ -115,31 +115,31 @@ void Font::drawText( QPainter *p, int x, int y, QChar *str, int slen, int pos, i
 
 #if APPLE_CHANGES
 
-float Font::floatWidth( QChar *chs, int slen, int pos, int len ) const
+float Font::floatWidth( QChar *chs, int slen, int pos, int len, int tabWidth, int xpos ) const
 {
-    return fm.floatWidth(chs, slen, pos, len, letterSpacing, wordSpacing, fontDef.smallCaps);
+    return fm.floatWidth(chs, slen, pos, len, tabWidth, xpos, letterSpacing, wordSpacing, fontDef.smallCaps);
 }
 
 
-void Font::floatCharacterWidths( QChar *str, int slen, int pos, int len, int toAdd, float *buffer) const
+void Font::floatCharacterWidths( QChar *str, int slen, int pos, int len, int toAdd, int tabWidth, int xpos, float *buffer) const
 {
-    fm.floatCharacterWidths(str, slen, pos, len, toAdd, buffer, letterSpacing, wordSpacing, fontDef.smallCaps);
+    fm.floatCharacterWidths(str, slen, pos, len, toAdd, tabWidth, xpos, buffer, letterSpacing, wordSpacing, fontDef.smallCaps);
 }
 
-int Font::checkSelectionPoint (QChar *s, int slen, int pos, int len, int toAdd, int x, bool reversed, bool includePartialGlyphs) const
+int Font::checkSelectionPoint (QChar *s, int slen, int pos, int len, int toAdd, int tabWidth, int xpos, int x, bool reversed, bool includePartialGlyphs) const
 {
-    return fm.checkSelectionPoint (s, slen, pos, len, toAdd, letterSpacing, wordSpacing, fontDef.smallCaps, x, reversed, includePartialGlyphs);
+    return fm.checkSelectionPoint (s, slen, pos, len, toAdd, tabWidth, xpos, letterSpacing, wordSpacing, fontDef.smallCaps, x, reversed, includePartialGlyphs);
 }
 
 #endif
 
-int Font::width( QChar *chs, int slen, int pos, int len ) const
+int Font::width( QChar *chs, int slen, int pos, int len, int tabWidth, int xpos ) const
 {
 #if APPLE_CHANGES
 #ifndef ROUND_TO_INT
 #define ROUND_TO_INT(x) (unsigned int)((x)+.5)
 #endif
-    return ROUND_TO_INT(fm.floatWidth(chs+pos, slen-pos, 0, len, letterSpacing, wordSpacing, fontDef.smallCaps));
+    return ROUND_TO_INT(fm.floatWidth(chs+pos, slen-pos, 0, len, tabWidth, xpos, letterSpacing, wordSpacing, fontDef.smallCaps));
 //    return fm.width(chs + pos, len);
 #else
     QString qstr = QConstString(chs+pos, len).string();
@@ -170,11 +170,11 @@ int Font::width( QChar *chs, int slen, int pos, int len ) const
 #endif
 }
 
-int Font::width( QChar *chs, int slen, int pos ) const
+int Font::width( QChar *chs, int slen, int tabWidth, int xpos ) const
 {
 #if APPLE_CHANGES
-//    return ROUND_TO_INT(fm.floatWidth(chs, slen, pos, 1, letterSpacing, wordSpacing));
-    return width(chs, slen, pos, 1);
+//    return ROUND_TO_INT(fm.floatWidth(chs, slen, pos, 1, tabWidth, xpos, letterSpacing, wordSpacing));
+    return width(chs, slen, 0, 1, tabWidth, xpos);
 #else
     int w;
     if ( !fontDef.hasNbsp && (chs+pos)->unicode() == 0xa0 )
@@ -186,7 +186,7 @@ int Font::width( QChar *chs, int slen, int pos ) const
        w += letterSpacing;
 
     if ( wordSpacing && (chs+pos)->isSpace() )
-               w += wordSpacing;
+        w += wordSpacing;
     return w;
 #endif
 }
index 07a4f4bd9529c691aa5648717c315756547225a5..0e228ac71ebd5140bfba81e1ac0844cb746a2dc7 100644 (file)
@@ -120,22 +120,22 @@ public:
 
                    
 #if !APPLE_CHANGES
-    void drawText( QPainter *p, int x, int y, QChar *str, int slen, int pos, int len, int width,
+    void drawText( QPainter *p, int x, int y, int tabWidth, int xpos, QChar *str, int slen, int pos, int len, int width,
                    QPainter::TextDirection d, int from=-1, int to=-1, QColor bg=QColor() ) const;
 
 #else
-    void drawText( QPainter *p, int x, int y, QChar *str, int slen, int pos, int len, int width,
+    void drawText( QPainter *p, int x, int y, int tabWidth, int xpos, QChar *str, int slen, int pos, int len, int width,
                    QPainter::TextDirection d, bool visuallyOrdered = false, int from=-1, int to=-1, QColor bg=QColor() ) const;
-    float floatWidth( QChar *str, int slen, int pos, int len ) const;
-    void floatCharacterWidths( QChar *str, int slen, int pos, int len, int toAdd, float *buffer) const;
+    float floatWidth( QChar *str, int slen, int pos, int len, int tabWidth, int xpos ) const;
+    void floatCharacterWidths( QChar *str, int slen, int pos, int len, int toAdd, int tabWidth, int xpos, float *buffer) const;
     bool isFixedPitch() const;
-    int checkSelectionPoint (QChar *s, int slen, int pos, int len, int toAdd, int x, bool reversed, bool includePartialGlyphs) const;
-    void drawHighlightForText( QPainter *p, int x, int y, int h, 
+    int checkSelectionPoint (QChar *s, int slen, int pos, int len, int toAdd, int tabWidth, int xpos, int x, bool reversed, bool includePartialGlyphs) const;
+    void drawHighlightForText( QPainter *p, int x, int y, int h, int tabWidth, int xpos, 
                    QChar *str, int slen, int pos, int len, int width,
                    QPainter::TextDirection d, bool visuallyOrdered = false, int from=-1, int to=-1, QColor bg=QColor()) const;
 #endif
-    int width( QChar *str, int slen, int pos, int len ) const;
-    int width( QChar *str, int slen, int pos ) const;
+    int width( QChar *str, int slen, int pos, int len, int tabWidth, int xpos ) const;
+    int width( QChar *str, int slen, int tabWidth, int xpos ) const;
 
     bool isSmallCaps() const { return fontDef.smallCaps; }
     
index f8596ef9d3fd9c5be8e5d8cf28ec7a254f605520..3ca5166b92096bcfeb5ccbaf34df5ebb589e33cb 100644 (file)
@@ -2796,7 +2796,7 @@ static void stripTrailingSpace(bool pre,
         RenderText* t = static_cast<RenderText *>(trailingSpaceChild);
         const Font *f = t->htmlFont( false );
         QChar space[1]; space[0] = ' ';
-        int spaceWidth = f->width(space, 1, 0);
+        int spaceWidth = f->width(space, 1, 0, 0);
         inlineMax -= spaceWidth;
         if (inlineMin > inlineMax)
             inlineMin = inlineMax;
@@ -2959,8 +2959,8 @@ void RenderBlock::calcInlineMinMaxWidth()
                 int beginMin, endMin;
                 bool beginWS, endWS;
                 int beginMax, endMax;
-                t->trimmedMinMaxWidth(beginMin, beginWS, endMin, endWS, hasBreakableChar,
-                                      hasBreak, beginMax, endMax,
+                t->trimmedMinMaxWidth(inlineMax, beginMin, beginWS, endMin, endWS,
+                                      hasBreakableChar, hasBreak, beginMax, endMax,
                                       childMin, childMax, stripFrontSpaces);
 
                 // This text object is insignificant and will not be rendered.  Just
index fd865a29eedd2c3b952bef7b4030092f9129ecc3..a3cfc6df9215dea5191fca125b91e011081b0640 100644 (file)
@@ -131,6 +131,7 @@ public:
     BidiIterator findNextLineBreak(BidiIterator &start, BidiState &info );
     RootInlineBox* constructLine(const BidiIterator& start, const BidiIterator& end);
     InlineFlowBox* createLineBoxes(RenderObject* obj);
+    int tabWidth(bool isWhitespacePre);
     void computeHorizontalPositionsForLine(RootInlineBox* lineBox, BidiState &bidi);
     void computeVerticalPositionsForLine(RootInlineBox* lineBox);
     void checkLinesForOverflow();
index 9202444de9694c16ca0c74116c3b0dfa05baaf48..03bf5b34341dee43a8cd9a72bc9a922baf6999db 100644 (file)
@@ -44,8 +44,8 @@ public:
  
     virtual QRect selectionRect() { return QRect(); }
 
-    virtual unsigned int width(unsigned int, unsigned int, const Font *) const { return 0; }
-    virtual unsigned int width( unsigned int, unsigned int, bool) const { return 0; }
+    virtual unsigned int width(unsigned int from, unsigned int len, const Font *f, int xpos) const { return 0; }
+    virtual unsigned int width(unsigned int from, unsigned int len, int xpos, bool firstLine = false) const { return 0; }
 
     virtual short lineHeight(bool firstLine, bool isRootLineBox=false) const;
     virtual short baselinePosition( bool firstLine, bool isRootLineBox=false) const;
index 74d7f211017ff154df603ac8c6ae30d2e0e2ea24..54bb45e4e98b395857e29ce03ccbc867cd63d5b9 100644 (file)
@@ -755,7 +755,7 @@ void RenderFlexibleBox::layoutVerticalBox(bool relayoutChildren)
                 const unsigned short ellipsisAndSpace[2] = { 0x2026, ' ' };
                 static AtomicString ellipsisAndSpaceStr(ellipsisAndSpace, 2);
                 const Font& font = style(numVisibleLines == 1)->htmlFont();
-                int ellipsisAndSpaceWidth = font.width(const_cast<QChar*>(ellipsisAndSpaceStr.unicode()), 2, 0, 2);
+                int ellipsisAndSpaceWidth = font.width(const_cast<QChar*>(ellipsisAndSpaceStr.unicode()), 2, 0, 2, 0, 0);
 
                 // Get ellipsis width + " " + anchor width
                 int totalWidth = ellipsisAndSpaceWidth + anchorBox->width();
index 257f9b9582f500f7da37daa7deb2f58012081002..eb832d169ffd798a67b94f181444e10fc48dc473 100644 (file)
@@ -113,7 +113,7 @@ void RenderImage::setPixmap( const QPixmap &p, const QRect& r, CachedImage *o)
         // we have an alt and the user meant it (its not a text we invented)
         if (!alt.isEmpty()) {
             const QFontMetrics &fm = style()->fontMetrics();
-            QRect br = fm.boundingRect (  0, 0, 1024, 256, Qt::AlignAuto|Qt::WordBreak, alt.string() );
+            QRect br = fm.boundingRect (  0, 0, 1024, 256, Qt::AlignAuto|Qt::WordBreak, alt.string(), 0, 0);  // FIX: correct tabwidth?
             if ( br.width() > iw )
                 iw = br.width();
             if ( br.height() > ih )
@@ -308,13 +308,12 @@ void RenderImage::paint(PaintInfo& i, int _tx, int _ty)
                 
                 // Only draw the alt text if it'll fit within the content box,
                 // and only if it fits above the error image.
-                int textWidth = fm.width (text, text.length());
+                int textWidth = fm.width (text, 0, 0, text.length());
                 if (errorPictureDrawn) {
                     if (usableWidth >= textWidth && fm.height() <= imageY)
-                        p->drawText(ax, ay+ascent, 0 /* ignored */, 0 /* ignored */, Qt::WordBreak  /* not supported */, text );
-                }
-                else if (usableWidth >= textWidth && cHeight >= fm.height())
-                    p->drawText(ax, ay+ascent, 0 /* ignored */, 0 /* ignored */, Qt::WordBreak  /* not supported */, text );
+                        p->drawText(ax, ay+ascent, tabWidth(), 0, 0 /* ignored */, 0 /* ignored */, Qt::WordBreak  /* not supported */, text );
+                } else if (usableWidth >= textWidth && cHeight >= fm.height())
+                    p->drawText(ax, ay+ascent, tabWidth(), 0, 0 /* ignored */, 0 /* ignored */, Qt::WordBreak  /* not supported */, text );
             }
 #else /* not APPLE_CHANGES */
             if ( !berrorPic ) {
@@ -337,7 +336,7 @@ void RenderImage::paint(PaintInfo& i, int _tx, int _ty)
                 int ay = _ty + topBorder + topPad + 2;
                 const QFontMetrics &fm = style()->fontMetrics();
                 if (cWidth>5 && cHeight>=fm.height())
-                    p->drawText(ax, ay+1, cWidth - 4, cHeight - 4, Qt::WordBreak, text );
+                    p->drawText(ax, ay+1, tabWidth(), 0, cWidth - 4, cHeight - 4, Qt::WordBreak, text );
             }
 #endif /* APPLE_CHANGES not defined */
         }
index 677a9d454731899a8979cb95864fae6cd274f337..569168dfcb75ebc7afd2c824acb0ef22ff4d1960 100644 (file)
@@ -1042,6 +1042,7 @@ void EllipsisBox::paint(RenderObject::PaintInfo& i, int _tx, int _ty)
     const DOMString& str = m_str.string();
     font->drawText(p, m_x + _tx, 
                       m_y + _ty + m_baseline,
+                      0, 0,
                       (str.implementation())->s,
                       str.length(), 0, str.length(),
                       0, 
index 1e959acbd5f14a1a8ccf22bac4cfeb74516fc14f..6a3701913a27ca3e3c7a8a214a7caeee5a3d24fe 100644 (file)
@@ -118,19 +118,19 @@ public:
     RootInlineBox* root();
     
     void setWidth(int w) { m_width = w; }
-    int width() { return m_width; }
+    int width() const { return m_width; }
 
     void setXPos(int x) { m_x = x; }
-    int xPos() { return m_x; }
+    int xPos() const { return m_x; }
 
     void setYPos(int y) { m_y = y; }
-    int yPos() { return m_y; }
+    int yPos() const { return m_y; }
 
     void setHeight(int h) { m_height = h; }
-    int height() { return m_height; }
+    int height() const { return m_height; }
     
     void setBaseline(int b) { m_baseline = b; }
-    int baseline() { return m_baseline; }
+    int baseline() const { return m_baseline; }
 
     virtual bool hasTextChildren() { return true; }
 
index 22f1a79b3c775b11ed7685d6b27919b329cd1222..d97e1565505e007996d356ae0d8347f2c2ac6fb5 100644 (file)
@@ -479,25 +479,25 @@ void RenderListMarker::paint(PaintInfo& i, int _tx, int _ty)
 
             if (isInside()) {
                if( style()->direction() == LTR) {
-                    p->drawText(_tx, _ty, 0, 0, Qt::AlignLeft|Qt::DontClip, m_item);
-                    p->drawText(_tx + fm.width(m_item), _ty, 0, 0, Qt::AlignLeft|Qt::DontClip, 
-                                QString::fromLatin1(". "));
+                    p->drawText(_tx, _ty, 0, 0, 0, 0, Qt::AlignLeft|Qt::DontClip, m_item);
+                    p->drawText(_tx + fm.width(m_item, 0, 0), _ty, 0, 0, 0, 0, Qt::AlignLeft|Qt::DontClip, 
+                            QString::fromLatin1(". "));
                 }
                else {
                     const QString& punct(QString::fromLatin1(" ."));
-                    p->drawText(_tx, _ty, 0, 0, Qt::AlignLeft|Qt::DontClip, punct);
-                   p->drawText(_tx + fm.width(punct), _ty, 0, 0, Qt::AlignLeft|Qt::DontClip, m_item);
+                    p->drawText(_tx, _ty, 0, 0, 0, 0, Qt::AlignLeft|Qt::DontClip, punct);
+                   p->drawText(_tx + fm.width(punct, 0, 0), _ty, 0, 0, 0, 0, Qt::AlignLeft|Qt::DontClip, m_item);
                 }
             } else {
                 if (style()->direction() == LTR) {
                     const QString& punct(QString::fromLatin1(". "));
-                    p->drawText(_tx-offset/2, _ty, 0, 0, Qt::AlignRight|Qt::DontClip, punct);
-                    p->drawText(_tx-offset/2-fm.width(punct), _ty, 0, 0, Qt::AlignRight|Qt::DontClip, m_item);
+                    p->drawText(_tx-offset/2, _ty, 0, 0, 0, 0, Qt::AlignRight|Qt::DontClip, punct);
+                    p->drawText(_tx-offset/2-fm.width(punct, 0, 0), _ty, 0, 0, 0, 0, Qt::AlignRight|Qt::DontClip, m_item);
                 }
                else {
                     const QString& punct(QString::fromLatin1(" ."));
-                   p->drawText(_tx+offset/2, _ty, 0, 0, Qt::AlignLeft|Qt::DontClip, punct);
-                    p->drawText(_tx+offset/2+fm.width(punct), _ty, 0, 0, Qt::AlignLeft|Qt::DontClip, m_item);
+                   p->drawText(_tx+offset/2, _ty, 0, 0, 0, 0, Qt::AlignLeft|Qt::DontClip, punct);
+                    p->drawText(_tx+offset/2+fm.width(punct, 0, 0), _ty, 0, 0, 0, 0, Qt::AlignLeft|Qt::DontClip, m_item);
                 }
             }
         }
@@ -601,8 +601,9 @@ void RenderListMarker::calcMinMaxWidth()
         break;
     }
 
-    if (isInside())
-        m_width = fm.width(m_item) + fm.width(QString::fromLatin1(". "));
+    if (isInside()) {
+        m_width = fm.width(m_item, 0, 0) + fm.width(QString::fromLatin1(". "), 0, 0);
+    }
 
 end:
 
index 3746931045ab920f45a8e93f57c5c90587c2895e..0884073c01581cec09c5b3192bd95a16c459eb96 100644 (file)
@@ -1736,6 +1736,11 @@ int RenderObject::paddingRight() const
     return w;
 }
 
+int RenderObject::tabWidth() const
+{
+    return containingBlock()->tabWidth(style()->whiteSpace() == PRE);
+}
+
 RenderCanvas* RenderObject::canvas() const
 {
     return static_cast<RenderCanvas*>(document()->renderer());
@@ -2048,9 +2053,6 @@ void RenderObject::recalcMinMaxWidths()
     
     RenderObject *child = firstChild();
     while( child ) {
-        // gcc sucks. if anybody knows a trick to get rid of the
-        // warning without adding an extra (unneeded) initialisation,
-        // go ahead
        int cmin = 0;
        int cmax = 0;
        bool test = false;
index de2d0ab5079a17907be51042449c2706fcd317f5..defc199a61fb6031e75d72cc31dc09b11a753350 100644 (file)
@@ -387,6 +387,8 @@ public:
     virtual short verticalPositionHint( bool firstLine ) const;
     // the offset of baseline from the top of the object.
     virtual short baselinePosition( bool firstLine, bool isRootLineBox=false ) const;
+    // width of tab character
+    int tabWidth() const;
 
     /*
      * Paint the object and its children, clipped by (x|y|w|h).
index 5143a90d1d3ec09f7daa5b58d61b4925e681df33..1b8861e286ffc5a2c67086b7b0791ad3f68a4ff7 100644 (file)
@@ -125,6 +125,8 @@ long RenderReplaced::caretMinOffset() const
 
 // Returns 1 since a replaced element can have the caret positioned 
 // at its beginning (0), or at its end (1).
+// NOTE: Yet, "select" elements can have any number of "option" elements
+// as children, so this "0 or 1" idea does not really hold up.
 long RenderReplaced::caretMaxOffset() const 
 { 
     return 1; 
index 376331204a5d6d01f617ed893c012f2969133935..f8019ded88365b1e4d37ca84c1e420c56578138a 100644 (file)
@@ -143,12 +143,12 @@ QRect InlineTextBox::selectionRect(int tx, int ty, int startPos, int endPos)
     int selEnd = selStart;
     int selTop = rootBox->selectionTop();
     int selHeight = rootBox->selectionHeight();
-    
+
     // FIXME: For justified text, just return the entire text box's rect.  At the moment there's still no easy
     // way to get the width of a run including the justification padding.
     if (sPos > 0 && !m_toAdd) {
         // The selection begins in the middle of our run.
-        int w = textObject()->width(m_start, sPos, m_firstLine);
+        int w = textObject()->width(m_start, sPos, m_firstLine, m_x);
         if (m_reversed)
             selStart -= w;
         else
@@ -162,14 +162,14 @@ QRect InlineTextBox::selectionRect(int tx, int ty, int startPos, int endPos)
             selEnd = m_x + m_width;
     }
     else {
-        // Our run is partially selected, and so we have to actually do a measurement.
+        // Our run is partially selected, and so we need to measure.
         int w = textObject()->width(sPos + m_start, ePos - sPos, m_firstLine);
         if (m_reversed)
             selEnd = selStart - w;
         else
             selEnd = selStart + w;
     }
-
+    
     int selLeft = m_reversed ? selEnd : selStart;
     int selRight = m_reversed ? selStart : selEnd;
 
@@ -383,7 +383,7 @@ void InlineTextBox::paint(RenderObject::PaintInfo& i, int tx, int ty)
         int endPoint = m_len;
         if (m_truncation != cNoTruncation)
             endPoint = m_truncation - m_start;
-        font->drawText(i.p, m_x + tx, m_y + ty + m_baseline,
+        font->drawText(i.p, m_x + tx, m_y + ty + m_baseline, textObject()->tabWidth(), textPos(),
                        textObject()->string()->s, textObject()->string()->l, m_start, endPoint,
                        m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, styleToUse->visuallyOrdered());
     } else {
@@ -392,18 +392,18 @@ void InlineTextBox::paint(RenderObject::PaintInfo& i, int tx, int ty)
         if (paintSelectedTextSeparately) {
             // paint only the text that is not selected
             if (sPos >= ePos) {
-                font->drawText(i.p, m_x + tx, m_y + ty + m_baseline,
+                font->drawText(i.p, m_x + tx, m_y + ty + m_baseline, textObject()->tabWidth(), textPos(),
                                textObject()->string()->s, textObject()->string()->l, m_start, m_len,
                                m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, styleToUse->visuallyOrdered());
             } else {
                 if (sPos - 1 >= 0) {
-                    font->drawText(i.p, m_x + tx, m_y + ty + m_baseline, textObject()->string()->s,
-                                   textObject()->string()->l, m_start, m_len,
+                    font->drawText(i.p, m_x + tx, m_y + ty + m_baseline, textObject()->tabWidth(), textPos(),
+                                   textObject()->string()->s, textObject()->string()->l, m_start, m_len,
                                    m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, styleToUse->visuallyOrdered(), 0, sPos);
                 }
                 if (ePos < m_start + m_len) {
-                    font->drawText(i.p, m_x + tx, m_y + ty + m_baseline, textObject()->string()->s,
-                                   textObject()->string()->l, m_start, m_len,
+                    font->drawText(i.p, m_x + tx, m_y + ty + m_baseline, textObject()->tabWidth(), textPos(),
+                                   textObject()->string()->s, textObject()->string()->l, m_start, m_len,
                                    m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, styleToUse->visuallyOrdered(), ePos, -1);
                 }
             }
@@ -419,8 +419,8 @@ void InlineTextBox::paint(RenderObject::PaintInfo& i, int tx, int ty)
                                selectionTextShadow->y,
                                selectionTextShadow->blur,
                                selectionTextShadow->color);
-            font->drawText(i.p, m_x + tx, m_y + ty + m_baseline, textObject()->string()->s,
-                           textObject()->string()->l, m_start, m_len,
+            font->drawText(i.p, m_x + tx, m_y + ty + m_baseline, textObject()->tabWidth(), textPos(),
+                           textObject()->string()->s, textObject()->string()->l, m_start, m_len,
                            m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, styleToUse->visuallyOrdered(), sPos, ePos);
             if (selectionTextShadow)
                 i.p->clearShadow();
@@ -524,10 +524,9 @@ void InlineTextBox::paintSelection(QPainter* p, int tx, int ty, RenderStyle* sty
     p->save();
     p->setPen(c); // Don't draw text at all!
     RootInlineBox* r = root();
-    int x = m_x + tx;
     int y = r->selectionTop();
     int h = r->selectionHeight();
-    f->drawHighlightForText(p, x, y + ty, h,
+    f->drawHighlightForText(p, m_x + tx, y + ty, h, textObject()->tabWidth(), textPos(), 
                             textObject()->str->s, textObject()->str->l, m_start, m_len,
                             m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, style->visuallyOrdered(), sPos, ePos, c);
     p->restore();
@@ -549,10 +548,9 @@ void InlineTextBox::paintMarkedTextBackground(QPainter* p, int tx, int ty, Rende
     p->setPen(c); // Don't draw text at all!
 
     RootInlineBox* r = root();
-    int x = m_x + tx;
     int y = r->selectionTop();
     int h = r->selectionHeight();
-    f->drawHighlightForText(p, x, y + ty, h, textObject()->str->s, textObject()->str->l, m_start, m_len,
+    f->drawHighlightForText(p, m_x + tx, y + ty, h, textObject()->tabWidth(), textPos(), textObject()->str->s, textObject()->str->l, m_start, m_len,
             m_toAdd, m_reversed ? QPainter::RTL : QPainter::LTR, style->visuallyOrdered(), sPos, ePos, c);
     p->restore();
 }
@@ -727,11 +725,21 @@ long RenderText::nextOffset (long current) const
     return current + 1;
 }
 
+int InlineTextBox::textPos() const
+{
+    if (xPos() == 0)
+        return 0;
+        
+    RenderBlock *blockElement = object()->containingBlock();
+    return m_reversed ? xPos() - blockElement->borderRight() - blockElement->paddingRight()
+                      : xPos() - blockElement->borderLeft() - blockElement->paddingLeft();
+}
+
 int InlineTextBox::offsetForPosition(int _x, bool includePartialGlyphs) const
 {
     RenderText* text = static_cast<RenderText*>(m_object);
     const Font* f = text->htmlFont(m_firstLine);
-    return f->checkSelectionPoint(text->str->s, text->str->l, m_start, m_len, m_toAdd, _x - m_x, m_reversed, includePartialGlyphs);
+    return f->checkSelectionPoint(text->str->s, text->str->l, m_start, m_len, m_toAdd, text->tabWidth(), textPos(), _x - m_x, m_reversed, includePartialGlyphs);
 }
 
 int InlineTextBox::positionForOffset(int offset) const
@@ -741,13 +749,13 @@ int InlineTextBox::positionForOffset(int offset) const
 
     int left;
     if (m_reversed) {
-        long len = m_start + m_len - offset;
-        QString string(text->str->s + offset, len);
-        left = m_x + fm.boundingRect(string, len).right();
+       long len = m_start + m_len - offset;
+       QString string(text->str->s + offset, len);
+       left = m_x + fm.boundingRect(string, text->tabWidth(), textPos(), len).right();
     } else {
-        long len = offset - m_start;
-        QString string(text->str->s + m_start, len);
-        left = m_x + fm.boundingRect(string, len).right();
+       long len = offset - m_start;
+       QString string(text->str->s + m_start, len);
+       left = m_x + fm.boundingRect(string, text->tabWidth(), textPos(), len).right();
     }
     // FIXME: Do we need to add rightBearing here?
     return left;
@@ -1141,7 +1149,7 @@ bool RenderText::shouldUseMonospaceCache(const Font *f) const
     return (f && f->isFixedPitch() && allAscii() && !style()->htmlFont().isSmallCaps());
 }
 
-// We cache the width of the ' ' character for <pre> text.  We could go futher
+// We cache the width of the ' ' character for <pre> text.  We could go further
 // and cache a widths array for all styles, at the expense of increasing the size of the
 // RenderText.
 void RenderText::cacheWidths()
@@ -1151,7 +1159,7 @@ void RenderText::cacheWidths()
     if (shouldUseMonospaceCache(f)){
         float fw;
         QChar c(' ');
-        f->floatCharacterWidths( &c, 1, 0, 1, 0, &fw);
+        f->floatCharacterWidths( &c, 1, 0, 1, 0, 0, 0, &fw);
         m_monospaceCharacterWidth = (int)fw;
     }
     else
@@ -1159,20 +1167,27 @@ void RenderText::cacheWidths()
 }
 
 
-inline int RenderText::widthFromCache(const Font *f, int start, int len) const
+inline int RenderText::widthFromCache(const Font *f, int start, int len, int tabWidth, int xpos) const
 {
     if (m_monospaceCharacterWidth != 0){
         int i, w = 0;
         for (i = start; i < start+len; i++){
-            int dir = str->s[i].direction();
-            if (dir != QChar::DirNSM && dir != QChar::DirBN)
-                w += m_monospaceCharacterWidth;
+            QChar c = str->s[i];
+            int dir = c.direction();
+            if (dir != QChar::DirNSM && dir != QChar::DirBN) {
+                if (c == '\t' && tabWidth != 0) {
+                    w += tabWidth - ((xpos + w) % tabWidth);
+                } else
+                    w += m_monospaceCharacterWidth;
+            }
         }
+
         return w;
     }
     
-    return f->width(str->s, str->l, start, len);
+    return f->width(str->s, str->l, start, len, tabWidth, xpos);
 }
+
 #ifdef XXX
 inline int RenderText::widthFromCache(const Font *f, int start, int len) const
 {
@@ -1186,7 +1201,8 @@ inline int RenderText::widthFromCache(const Font *f, int start, int len) const
 
 #endif
 
-void RenderText::trimmedMinMaxWidth(int& beginMinW, bool& beginWS, 
+void RenderText::trimmedMinMaxWidth(int leadWidth,
+                                    int& beginMinW, bool& beginWS, 
                                     int& endMinW, bool& endWS,
                                     bool& hasBreakableChar, bool& hasBreak,
                                     int& beginMaxW, int& endMaxW,
@@ -1203,6 +1219,10 @@ void RenderText::trimmedMinMaxWidth(int& beginMinW, bool& beginWS,
         return;
     }
     
+    // if the text has a variable width tab, we need to call 
+    if (m_hasTab)
+        calcMinMaxWidth(leadWidth);
+    
     minW = m_minWidth;
     maxW = m_maxWidth;
     beginWS = stripFrontSpaces ? false : m_hasBeginWS;
@@ -1214,10 +1234,10 @@ void RenderText::trimmedMinMaxWidth(int& beginMinW, bool& beginWS,
     hasBreakableChar = m_hasBreakableChar;
     hasBreak = m_hasBreak;
 
-    if (stripFrontSpaces && (str->s[0] == ' ' || (!isPre && str->s[0] == '\n'))) {
+    if (stripFrontSpaces && (str->s[0] == ' ' || (!isPre && (str->s[0] == '\n' || str->s[0] == '\t')))) {
         const Font *f = htmlFont( false );
         QChar space[1]; space[0] = ' ';
-        int spaceWidth = f->width(space, 1, 0);
+        int spaceWidth = f->width(space, 1, 0, 0);
         maxW -= spaceWidth;
     }
     
@@ -1242,12 +1262,13 @@ void RenderText::trimmedMinMaxWidth(int& beginMinW, bool& beginWS,
             if (linelen)
             {
 #if !APPLE_CHANGES
-                endMaxW = f->width(str->s, str->l, i, linelen);
+                endMaxW = f->width(str->s, str->l, i, linelen, tabWidth(), leadWidth + endMaxW); 
 #else
-                endMaxW = widthFromCache(f, i, linelen);
+                endMaxW = widthFromCache(f, i, linelen, tabWidth(), leadWidth + endMaxW);
 #endif
                 if (firstLine) {
                     firstLine = false;
+                    leadWidth = 0;
                     beginMaxW = endMaxW;
                 }
                 i += linelen;
@@ -1255,6 +1276,7 @@ void RenderText::trimmedMinMaxWidth(int& beginMinW, bool& beginWS,
             else if (firstLine) {
                 beginMaxW = 0;
                 firstLine = false;
+                leadWidth = 0;
             }
     
             if (i == len-1)
@@ -1267,8 +1289,14 @@ void RenderText::trimmedMinMaxWidth(int& beginMinW, bool& beginWS,
 
 void RenderText::calcMinMaxWidth()
 {
+    // Use 0 for the leadWidth.   If the text contains a variable width tab, the real width
+    // will get measured when trimmedMinMaxWidth calls again with the real leadWidth.
     KHTMLAssert( !minMaxKnown() );
+    calcMinMaxWidth(0);
+}
 
+void RenderText::calcMinMaxWidth(int leadWidth)
+{
     // ### calc Min and Max width...
     m_minWidth = m_beginMinWidth = m_endMinWidth = 0;
     m_maxWidth = 0;
@@ -1278,7 +1306,7 @@ void RenderText::calcMinMaxWidth()
         
     int currMinWidth = 0;
     int currMaxWidth = 0;
-    m_hasBreakableChar = m_hasBreak = m_hasBeginWS = m_hasEndWS = false;
+    m_hasBreakableChar = m_hasBreak = m_hasTab = m_hasBeginWS = m_hasEndWS = false;
     
     // ### not 100% correct for first-line
     const Font *f = htmlFont( false );
@@ -1301,8 +1329,13 @@ void RenderText::calcMinMaxWidth()
                 m_hasBreak = true;
                 isNewline = true;
                 isSpace = false;
-            }
-            else
+            } else
+                isSpace = true;
+        } else if (c == '\t') {
+            if (isPre) {
+                m_hasTab = true;
+                isSpace = false;
+            } else
                 isSpace = true;
         } else {
             isSpace = c == ' ';
@@ -1318,12 +1351,14 @@ void RenderText::calcMinMaxWidth()
         
         if (ignoringSpaces && !isSpace)
             ignoringSpaces = false;
-            
-        if (ignoringSpaces || (i > 0 && c.unicode() == SOFT_HYPHEN)) // Ignore spaces and soft hyphens
+        
+        // Ignore spaces and soft hyphens
+        if (ignoringSpaces || (i > 0 && c.unicode() == SOFT_HYPHEN)) {
             continue;
+        }
         
         int wordlen = 0;
-        while (i+wordlen < len && str->s[i+wordlen] != '\n' && str->s[i+wordlen] != ' ' &&
+        while (i+wordlen < len && str->s[i+wordlen] != '\n' && str->s[i+wordlen] != ' ' && str->s[i+wordlen] != '\t' &&
                (i+wordlen == 0 || str->s[i+wordlen].unicode() != SOFT_HYPHEN) && // Skip soft hyphens
                (wordlen == 0 || !isBreakable( str->s, i+wordlen, str->l)))
             wordlen++;
@@ -1331,20 +1366,20 @@ void RenderText::calcMinMaxWidth()
         if (wordlen)
         {
 #if !APPLE_CHANGES
-            int w = f->width(str->s, str->l, i, wordlen);
+            int w = f->width(str->s, str->l, i, wordlen, tabWidth(), leadWidth + currMaxWidth);
 #else
-            int w = widthFromCache(f, i, wordlen);
+            int w = widthFromCache(f, i, wordlen, tabWidth(), leadWidth + currMaxWidth);
 #endif
             currMinWidth += w;
             currMaxWidth += w;
             
-            bool isBreakableCharSpace = (i+wordlen < len) ? ((!isPre && str->s[i+wordlen] == '\n') || 
+            bool isBreakableCharSpace = (i+wordlen < len) ? ((!isPre && (str->s[i+wordlen] == '\n' || str->s[i+wordlen] == '\t')) || 
                                                              str->s[i+wordlen] == ' ') : false;
 
             if (i+wordlen < len && style()->whiteSpace() == NORMAL)
                 m_hasBreakableChar = true;
             
-            // Add in wordspacing to our maxwidth, but not if this is the last word on a line or the
+            // Add in wordSpacing to our currMaxWidth, but not if this is the last word on a line or the
             // last word in the run.
             if (wordSpacing && isBreakableCharSpace && !containsOnlyWhitespace(i+wordlen, len-(i+wordlen)))
                 currMaxWidth += wordSpacing;
@@ -1368,7 +1403,7 @@ void RenderText::calcMinMaxWidth()
         }
         else {
             // Nowrap can never be broken, so don't bother setting the
-            // breakable character boolean. Pre can only be broken if we encounter a newline.
+            // breakable character boolean. Pre can only be broken if we encounter a newline.     
             if (style()->whiteSpace() == NORMAL || isNewline)
                 m_hasBreakableChar = true;
 
@@ -1379,6 +1414,7 @@ void RenderText::calcMinMaxWidth()
             {
                 if (firstLine) {
                     firstLine = false;
+                    leadWidth = 0;
                     m_beginMinWidth = currMaxWidth;
                 }
                 
@@ -1387,14 +1423,14 @@ void RenderText::calcMinMaxWidth()
             }
             else
             {
-                currMaxWidth += f->width( str->s, str->l, i + wordlen );
+                currMaxWidth += f->width(str->s, str->l, i + wordlen, 1, tabWidth(), leadWidth + currMaxWidth);
             }
         }
     }
-    
+
     if(currMinWidth > m_minWidth) m_minWidth = currMinWidth;
     if(currMaxWidth > m_maxWidth) m_maxWidth = currMaxWidth;
-
+        
     if (style()->whiteSpace() != NORMAL)
         m_minWidth = m_maxWidth;
 
@@ -1412,7 +1448,7 @@ bool RenderText::containsOnlyWhitespace(unsigned int from, unsigned int len) con
 {
     unsigned int currPos;
     for (currPos = from; 
-         currPos < from+len && (str->s[currPos] == '\n' || str->s[currPos].unicode() == ' '); 
+         currPos < from+len && (str->s[currPos] == '\n' || str->s[currPos].unicode() == ' ' || str->s[currPos] == '\t'); 
          currPos++);
     return currPos >= (from+len);
 }
@@ -1659,37 +1695,37 @@ void RenderText::position(InlineBox* box, int from, int len, bool reverse)
     s->m_len = len;
 }
 
-unsigned int RenderText::width(unsigned int from, unsigned int len, bool firstLine) const
+unsigned int RenderText::width(unsigned int from, unsigned int len, int xpos, bool firstLine) const
 {
     if(!str->s || from > str->l ) return 0;
     if ( from + len > str->l ) len = str->l - from;
 
     const Font *f = htmlFont( firstLine );
-    return width( from, len, f );
+    return width( from, len, f, xpos );
 }
 
-unsigned int RenderText::width(unsigned int from, unsigned int len, const Font *f) const
+unsigned int RenderText::width(unsigned int from, unsigned int len, const Font *f, int xpos) const
 {
     if(!str->s || from > str->l ) return 0;
     if ( from + len > str->l ) len = str->l - from;
 
     int w;
-    if ( f == &style()->htmlFont() && from == 0 && len == str->l )
+    if ( style()->whiteSpace() != PRE && f == &style()->htmlFont() && from == 0 && len == str->l ) {
         w = m_maxWidth;
 #if APPLE_CHANGES
-    else if (f == &style()->htmlFont())
-        w = widthFromCache (f, from, len);
+    } else if (f == &style()->htmlFont()) {
+        w = widthFromCache (f, from, len, tabWidth(), xpos);
 #endif
-    else
-        w = f->width(str->s, str->l, from, len );
-
+    } else {
+       w = f->width(str->s, str->l, from, len, tabWidth(), xpos );
+    }
+        
     //kdDebug( 6040 ) << "RenderText::width(" << from << ", " << len << ") = " << w << endl;
     return w;
 }
 
 int RenderText::width() const
 {
-    int w;
     int minx = 100000000;
     int maxx = 0;
     // slooow
@@ -1700,9 +1736,7 @@ int RenderText::width() const
             maxx = s->m_x + s->m_width;
     }
 
-    w = kMax(0, maxx-minx);
-
-    return w;
+    return kMax(0, maxx-minx);
 }
 
 QRect RenderText::getAbsoluteRepaintRect()
index d3d2ad38cedac7e60941bd601ada2a94e9ad9cab..c54b2ab3b522f388c8d89142d9979f36697dfad9 100644 (file)
@@ -124,6 +124,7 @@ public:
     virtual long caretMaxOffset() const;
     virtual unsigned long caretMaxRenderedOffset() const;
     
+    int textPos() const;
     int offsetForPosition(int _x, bool includePartialGlyphs = true) const;
     int positionForOffset(int offset) const;
     
@@ -190,8 +191,8 @@ public:
     unsigned int stringLength() const { return str->l; } // non virtual implementation of length()
     virtual void position(InlineBox* box, int from, int len, bool reverse);
 
-    virtual unsigned int width(unsigned int from, unsigned int len, const Font *f) const;
-    virtual unsigned int width(unsigned int from, unsigned int len, bool firstLine = false) const;
+    virtual unsigned int width(unsigned int from, unsigned int len, const Font *f, int xpos) const;
+    virtual unsigned int width(unsigned int from, unsigned int len, int xpos, bool firstLine = false) const;
     virtual int width() const;
     virtual int height() const;
 
@@ -203,7 +204,11 @@ public:
     virtual void calcMinMaxWidth();
     virtual int minWidth() const { return m_minWidth; }
     virtual int maxWidth() const { return m_maxWidth; }
-    virtual void trimmedMinMaxWidth(int& beginMinW, bool& beginWS, 
+
+    // widths
+    void calcMinMaxWidth(int leadWidth);
+    virtual void trimmedMinMaxWidth(int leadWidth,
+                                    int& beginMinW, bool& beginWS, 
                                     int& endMinW, bool& endWS,
                                     bool& hasBreakableChar, bool& hasBreak,
                                     int& beginMaxW, int& endMaxW,
@@ -248,7 +253,7 @@ public:
     virtual InlineBox *inlineBox(long offset, EAffinity affinity = UPSTREAM);
 
 #if APPLE_CHANGES
-    int widthFromCache(const Font *, int start, int len) const;
+    int widthFromCache(const Font *, int start, int len, int tabWidth, int xpos) const;
     bool shouldUseMonospaceCache(const Font *) const;
     void cacheWidths();
     bool allAscii() const;
@@ -280,6 +285,7 @@ protected: // members
     SelectionState m_selectionState : 3 ;
     bool m_hasBreakableChar : 1; // Whether or not we can be broken into multiple lines.
     bool m_hasBreak : 1; // Whether or not we have a hard break (e.g., <pre> with '\n').
+    bool m_hasTab : 1; // Whether or not we have a variable width tab character (e.g., <pre> with '\t').
     bool m_hasBeginWS : 1; // Whether or not we begin with WS (only true if we aren't pre)
     bool m_hasEndWS : 1; // Whether or not we end with WS (only true if we aren't pre)
     
index 29477eb2a990c72473e3ed07c4dd6d42a1b1b0dd..2dcb44a530a9542f2d234a5d733a2d246ead033e 100644 (file)
@@ -51,21 +51,21 @@ public:
     int lineSpacing() const;
     float xHeight() const;
     
-    int width(QChar) const;
-    int width(char) const;
-    int width(const QString &, int len=-1) const;
-    int charWidth(const QString &, int pos) const;
-    int width(const QChar *, int len) const;
+    int width(QChar, int tabWidth, int xpos) const;
+    int width(char, int tabWidth, int xpos) const;
+    int width(const QString &, int tabWidth, int xpos, int len=-1) const;
+    int charWidth(const QString &, int pos, int tabWidth, int xpos) const;
+    int width(const QChar *, int len, int tabWidth, int xpos) const;
     float floatWidth(const QChar *, int slen, int pos, int len,
-                     int letterSpacing, int wordSpacing, bool smallCaps) const;
-    float floatCharacterWidths(const QChar *, int slen, int pos, int len, int toAdd, float *buffer,
+                     int tabWidth, int xpos, int letterSpacing, int wordSpacing, bool smallCaps) const;
+    float floatCharacterWidths(const QChar *, int slen, int pos, int len, int toAdd, int tabWidth, int xpos, float *buffer,
                                int letterSpacing, int wordSpacing, bool smallCaps) const;
-    int checkSelectionPoint (QChar *s, int slen, int pos, int len, int toAdd, int letterSpacing, int wordSpacing, bool smallCaps, int x, bool reversed, bool includePartialGlyphs) const;
+    int checkSelectionPoint (QChar *s, int slen, int pos, int len, int toAdd, int tabWidth, int xpos, int letterSpacing, int wordSpacing, bool smallCaps, int x, bool reversed, bool includePartialGlyphs) const;
 
-    QRect boundingRect(const QString &, int len=-1) const;
-    QRect boundingRect(int, int, int, int, int, const QString &) const;
+    QRect boundingRect(const QString &, int tabWidth, int xpos, int len=-1) const;
+    QRect boundingRect(int, int, int, int, int, const QString &, int tabWidth, int xpos) const;
 
-    QSize size(int, const QString &) const;
+    QSize size(int, const QString &, int tabWidth, int xpos) const;
 
     int baselineOffset() const { return ascent(); }
     
index 631e83e4788305e5aa874511d471e9c0ca4de48f..8ac646c185ea4eaf596c8a854ccce8bf3c92c39f 100644 (file)
@@ -158,7 +158,7 @@ float QFontMetrics::xHeight() const
     return [data->getRenderer() xHeight];
 }
 
-int QFontMetrics::width(QChar qc) const
+int QFontMetrics::width(QChar qc, int tabWidth, int xpos) const
 {
     if (data.isNull()) {
         ERROR("called width on an empty QFontMetrics");
@@ -175,16 +175,18 @@ int QFontMetrics::width(QChar qc) const
     WebCoreTextStyle style;
     WebCoreInitializeEmptyTextStyle(&style);
     style.families = families;
+    style.tabWidth = tabWidth;
+    style.xpos = xpos;
 
     return ROUND_TO_INT([data->getRenderer() floatWidthForRun:&run style:&style widths:0]);
 }
 
-int QFontMetrics::charWidth(const QString &s, int pos) const
+int QFontMetrics::charWidth(const QString &s, int pos, int tabWidth, int xpos) const
 {
-    return width(s[pos]);
+    return width(s[pos], tabWidth, xpos);
 }
 
-int QFontMetrics::width(char c) const
+int QFontMetrics::width(char c, int tabWidth, int xpos) const
 {
     if (data.isNull()) {
         ERROR("called width on an empty QFontMetrics");
@@ -201,11 +203,13 @@ int QFontMetrics::width(char c) const
     WebCoreTextStyle style;
     WebCoreInitializeEmptyTextStyle(&style);
     style.families = families;
+    style.tabWidth = tabWidth;
+    style.xpos = xpos;
 
     return ROUND_TO_INT([data->getRenderer() floatWidthForRun:&run style:&style widths:0]);
 }
 
-int QFontMetrics::width(const QString &qstring, int len) const
+int QFontMetrics::width(const QString &qstring, int tabWidth, int xpos, int len) const
 {
     if (data.isNull()) {
         ERROR("called width on an empty QFontMetrics");
@@ -222,11 +226,13 @@ int QFontMetrics::width(const QString &qstring, int len) const
     WebCoreTextStyle style;
     WebCoreInitializeEmptyTextStyle(&style);
     style.families = families;
+    style.tabWidth = tabWidth;
+    style.xpos = xpos;
 
     return ROUND_TO_INT([data->getRenderer() floatWidthForRun:&run style:&style widths:0]);
 }
 
-int QFontMetrics::width(const QChar *uchars, int len) const
+int QFontMetrics::width(const QChar *uchars, int len, int tabWidth, int xpos) const
 {
     if (data.isNull()) {
         ERROR("called width on an empty QFontMetrics");
@@ -241,12 +247,14 @@ int QFontMetrics::width(const QChar *uchars, int len) const
     WebCoreTextStyle style;
     WebCoreInitializeEmptyTextStyle(&style);
     style.families = families;
+    style.tabWidth = tabWidth;
+    style.xpos = xpos;
 
     return ROUND_TO_INT([data->getRenderer() floatWidthForRun:&run style:&style widths:0]);
 }
 
 float QFontMetrics::floatWidth(const QChar *uchars, int slen, int pos, int len,
-                               int letterSpacing, int wordSpacing, bool smallCaps) const
+                               int tabWidth, int xpos, int letterSpacing, int wordSpacing, bool smallCaps) const
 {
     if (data.isNull()) {
         ERROR("called floatWidth on an empty QFontMetrics");
@@ -260,6 +268,8 @@ float QFontMetrics::floatWidth(const QChar *uchars, int slen, int pos, int len,
     
     WebCoreTextStyle style;
     WebCoreInitializeEmptyTextStyle(&style);
+    style.tabWidth = tabWidth;
+    style.xpos = xpos;
     style.letterSpacing = letterSpacing;
     style.wordSpacing = wordSpacing;
     style.smallCaps = smallCaps;
@@ -268,7 +278,7 @@ float QFontMetrics::floatWidth(const QChar *uchars, int slen, int pos, int len,
     return ROUND_TO_INT([data->getRenderer() floatWidthForRun:&run style:&style widths:0]);
 }
 
-float QFontMetrics::floatCharacterWidths(const QChar *uchars, int slen, int pos, int len, int toAdd, float *buffer, int letterSpacing, int wordSpacing, bool smallCaps) const
+float QFontMetrics::floatCharacterWidths(const QChar *uchars, int slen, int pos, int len, int toAdd, int tabWidth, int xpos, float *buffer, int letterSpacing, int wordSpacing, bool smallCaps) const
 {
     if (data.isNull()) {
         ERROR("called floatCharacterWidths on an empty QFontMetrics");
@@ -286,12 +296,14 @@ float QFontMetrics::floatCharacterWidths(const QChar *uchars, int slen, int pos,
     style.wordSpacing = wordSpacing;
     style.smallCaps = smallCaps;
     style.padding = toAdd;
+    style.tabWidth = tabWidth;
+    style.xpos = xpos;
     style.families = families;
 
     return [data->getRenderer() floatWidthForRun:&run style:&style widths:buffer];
 }
 
-int QFontMetrics::checkSelectionPoint (QChar *s, int slen, int pos, int len, int toAdd, int letterSpacing, int wordSpacing, bool smallCaps, int x, bool reversed, bool includePartialGlyphs) const
+int QFontMetrics::checkSelectionPoint (QChar *s, int slen, int pos, int len, int toAdd, int tabWidth, int xpos, int letterSpacing, int wordSpacing, bool smallCaps, int x, bool reversed, bool includePartialGlyphs) const
 {
     if (data.isNull()) {
         ERROR("called floatWidth on an empty QFontMetrics");
@@ -309,23 +321,25 @@ int QFontMetrics::checkSelectionPoint (QChar *s, int slen, int pos, int len, int
     style.smallCaps = smallCaps;
     style.families = families;
     style.padding = toAdd;
+    style.tabWidth = tabWidth;
+    style.xpos = xpos;
     style.rtl = reversed;
 
     return [data->getRenderer() pointToOffset:&run style:&style position:x reversed:reversed includePartialGlyphs:includePartialGlyphs];
 }
 
-QRect QFontMetrics::boundingRect(const QString &qstring, int len) const
+QRect QFontMetrics::boundingRect(const QString &qstring, int tabWidth, int xpos, int len) const
 {
-    return QRect(0, 0, width(qstring, len), height());
+    return QRect(0, 0, width(qstring, tabWidth, xpos, len), height());
 }
 
-QRect QFontMetrics::boundingRect(int x, int y, int width, int height, int flags, const QString &str) const
+QRect QFontMetrics::boundingRect(int x, int y, int width, int height, int flags, const QString &str, int tabWidth, int xpos) const
 {
     // FIXME: need to support word wrapping?
-    return QRect(x, y, width, height).intersect(boundingRect(str));
+    return QRect(x, y, width, height).intersect(boundingRect(str, tabWidth, xpos));
 }
 
-QSize QFontMetrics::size(int, const QString &qstring) const
+QSize QFontMetrics::size(int, const QString &qstring, int tabWidth, int xpos) const
 {
-    return QSize(width(qstring), height());
+    return QSize(width(qstring, tabWidth, xpos), height());
 }
index 27ada0bc74e28d95637a33788ee001e860b0f92d..dc1022e2cf920b7ff99d3ecf16ab6fe2d15aa40b 100644 (file)
@@ -101,12 +101,12 @@ public:
     RasterOp rasterOp() const;
     void setRasterOp(RasterOp);
 
-    void drawText(int x, int y, int, int, int alignmentFlags, const QString &);
-    void drawHighlightForText(int x, int y, int h, 
+    void drawText(int x, int y, int tabWidth, int xpos, int, int, int alignmentFlags, const QString &);
+    void drawHighlightForText(int x, int y, int h, int tabWidth, int xpos,
                   const QChar *, int length, int from, int to, int toAdd,
                   const QColor& backgroundColor, QPainter::TextDirection d, bool visuallyOrdered,
                   int letterSpacing, int wordSpacing, bool smallCaps);
-    void drawText(int x, int y, const QChar *, int length, int from, int to, int toAdd,
+    void drawText(int x, int y, int tabWidth, int xpos, const QChar *, int length, int from, int to, int toAdd,
                   const QColor& backgroundColor, QPainter::TextDirection d, bool visuallyOrdered,
                   int letterSpacing, int wordSpacing, bool smallCaps);
     void drawLineForText(int x, int y, int yOffset, int width);
index 546105eb24bb39412fc0c408e92d2101985de78c..f54d7ebca0d4f700bae22912fb38b28e3882cfee 100644 (file)
@@ -597,7 +597,7 @@ void QPainter::_updateRenderer()
     }
 }
     
-void QPainter::drawText(int x, int y, int, int, int alignmentFlags, const QString &qstring)
+void QPainter::drawText(int x, int y, int tabWidth, int xpos, int, int, int alignmentFlags, const QString &qstring)
 {
     if (data->state.paintingDisabled)
         return;
@@ -617,6 +617,8 @@ void QPainter::drawText(int x, int y, int, int, int alignmentFlags, const QStrin
     WebCoreInitializeEmptyTextStyle(&style);
     style.textColor = data->state.pen.color().getNSColor();
     style.families = families;
+    style.tabWidth = tabWidth;
+    style.xpos = xpos;
     
     if (alignmentFlags & Qt::AlignRight)
         x -= ROUND_TO_INT([data->textRenderer floatWidthForRun:&run style:&style widths:0]);
@@ -624,11 +626,10 @@ void QPainter::drawText(int x, int y, int, int, int alignmentFlags, const QStrin
     WebCoreTextGeometry geometry;
     WebCoreInitializeEmptyTextGeometry(&geometry);
     geometry.point = NSMakePoint(x, y);
-     
     [data->textRenderer drawRun:&run style:&style geometry:&geometry];
 }
 
-void QPainter::drawText(int x, int y, const QChar *str, int len, int from, int to, int toAdd, const QColor &backgroundColor, QPainter::TextDirection d, bool visuallyOrdered, int letterSpacing, int wordSpacing, bool smallCaps)
+void QPainter::drawText(int x, int y, int tabWidth, int xpos, const QChar *str, int len, int from, int to, int toAdd, const QColor &backgroundColor, QPainter::TextDirection d, bool visuallyOrdered, int letterSpacing, int wordSpacing, bool smallCaps)
 {
     if (data->state.paintingDisabled || len <= 0)
         return;
@@ -657,14 +658,15 @@ void QPainter::drawText(int x, int y, const QChar *str, int len, int from, int t
     style.smallCaps = smallCaps;
     style.families = families;
     style.padding = toAdd;
+    style.tabWidth = tabWidth;
+    style.xpos = xpos;
     WebCoreTextGeometry geometry;
     WebCoreInitializeEmptyTextGeometry(&geometry);
     geometry.point = NSMakePoint(x, y);
-    
     [data->textRenderer drawRun:&run style:&style geometry:&geometry];
 }
 
-void QPainter::drawHighlightForText(int x, int y, int h, 
+void QPainter::drawHighlightForText(int x, int y, int h, int tabWidth, int xpos,
     const QChar *str, int len, int from, int to, int toAdd, const QColor &backgroundColor, 
     QPainter::TextDirection d, bool visuallyOrdered, int letterSpacing, int wordSpacing, bool smallCaps)
 {
@@ -695,6 +697,8 @@ void QPainter::drawHighlightForText(int x, int y, int h,
     style.smallCaps = smallCaps;
     style.families = families;    
     style.padding = toAdd;
+    style.tabWidth = tabWidth;
+    style.xpos = xpos;
     WebCoreTextGeometry geometry;
     WebCoreInitializeEmptyTextGeometry(&geometry);
     geometry.point = NSMakePoint(x, y);
index bfa82c194abb7bae8a256de9f15a897c6fdaa5b8..cc4c9e930be582a62901d43ae0959340c880d9d1 100644 (file)
@@ -36,6 +36,8 @@ struct WebCoreTextStyle
     int letterSpacing;
     int wordSpacing;
     int padding;
+    int tabWidth;
+    int xpos;
     NSString **families;
     unsigned smallCaps : 1;
     unsigned rtl : 1;
index be13240f54612ac32cd5d0697d42fa23bb0f73a0..23bd04c4e2789d62224556d8c04d0cdc226c0d02 100644 (file)
@@ -42,6 +42,8 @@ void WebCoreInitializeTextRun(WebCoreTextRun *run, const UniChar *characters, un
 void WebCoreInitializeEmptyTextStyle(WebCoreTextStyle *style)
 {
     style->padding = 0;
+    style->tabWidth = 0;
+    style->xpos = 0;
     style->textColor = nil;
     style->backgroundColor = nil;
     style->rtl = false;