2011-03-31  Evan Martin  <evan@chromium.org>

        Reviewed by Eric Seidel.

        <title> should support dir attribute
        https://bugs.webkit.org/show_bug.cgi?id=50961

        Introduce a new StringWithDirection object that carries a String along
        with the TextDirection associated with the String.  Use this object for
        document titles used within WebCore, because in HTML the direction of
        a title can be set with the 'dir' attribute.

        Put FIXMEs at the WebKit level to expose the new direction information
        to clients.

        No behavioral change intended, so no new tests.  A follow-up will expose
        the title direction and hopefully can be accompanied by tests that
        verify it is correct.

        * dom/Document.cpp:
        (WebCore::Document::Document):
        (WebCore::Document::updateTitle):
        (WebCore::Document::setTitle):
        (WebCore::Document::removeTitle):
        * dom/Document.h:
        (WebCore::Document::title):
        * html/HTMLTitleElement.cpp:
        (WebCore::HTMLTitleElement::HTMLTitleElement):
        (WebCore::HTMLTitleElement::childrenChanged):
        (WebCore::HTMLTitleElement::text):
        (WebCore::HTMLTitleElement::textWithDirection):
        * html/HTMLTitleElement.h:
        * loader/DocumentLoader.cpp:
        (WebCore::DocumentLoader::setTitle):
        * loader/DocumentLoader.h:
        (WebCore::DocumentLoader::title):
        * loader/EmptyClients.h:
        (WebCore::EmptyFrameLoaderClient::dispatchDidReceiveTitle):
        (WebCore::EmptyFrameLoaderClient::setTitle):
        * loader/FrameLoader.cpp:
        (WebCore::FrameLoader::receivedFirstData):
        (WebCore::FrameLoader::commitProvisionalLoad):
        (WebCore::FrameLoader::setTitle):
        * loader/FrameLoader.h:
        * loader/FrameLoaderClient.h:
        * loader/HistoryController.cpp:
        (WebCore::HistoryController::updateForBackForwardNavigation):
        (WebCore::HistoryController::updateForReload):
        (WebCore::HistoryController::updateForRedirectWithLockedBackForwardList):
        (WebCore::HistoryController::updateForClientRedirect):
        (WebCore::HistoryController::updateForCommit):
        (WebCore::HistoryController::setCurrentItemTitle):
        (WebCore::HistoryController::initializeItem):
        * loader/HistoryController.h:
        * platform/text/StringWithDirection.h: Added.
        (WebCore::StringWithDirection::StringWithDirection):
        (WebCore::StringWithDirection::operator==):
        (WebCore::StringWithDirection::operator!=):
        * svg/SVGTitleElement.cpp:
        (WebCore::SVGTitleElement::insertedIntoDocument):
        (WebCore::SVGTitleElement::childrenChanged):
2011-03-31  Evan Martin  <evan@chromium.org>

        Reviewed by Eric Seidel.

        <title> should support dir attribute
        https://bugs.webkit.org/show_bug.cgi?id=50961

        Update to new FrameLoaderClient interface.

        * src/FrameLoaderClientImpl.cpp:
        (WebKit::FrameLoaderClientImpl::dispatchDidReceiveTitle):
        (WebKit::FrameLoaderClientImpl::setTitle):
        * src/FrameLoaderClientImpl.h:
        * src/WebDataSourceImpl.cpp:
        (WebKit::WebDataSourceImpl::pageTitle):
2011-03-31  Evan Martin  <evan@chromium.org>

        Reviewed by Eric Seidel.

        <title> should support dir attribute
        https://bugs.webkit.org/show_bug.cgi?id=50961

        Update to new FrameLoaderClient interface.

        * WebCoreSupport/FrameLoaderClientEfl.cpp:
        (WebCore::FrameLoaderClientEfl::dispatchDidReceiveTitle):
        (WebCore::FrameLoaderClientEfl::setTitle):
        * WebCoreSupport/FrameLoaderClientEfl.h:
2011-03-31  Evan Martin  <evan@chromium.org>

        Reviewed by Eric Seidel.

        <title> should support dir attribute
        https://bugs.webkit.org/show_bug.cgi?id=50961

        Update to new FrameLoaderClient interface.

        * WebCoreSupport/FrameLoaderClientGtk.cpp:
        (WebKit::FrameLoaderClient::dispatchDidReceiveTitle):
        (WebKit::FrameLoaderClient::setTitle):
        * WebCoreSupport/FrameLoaderClientGtk.h:
2011-03-31  Evan Martin  <evan@chromium.org>

        Reviewed by Eric Seidel.

        <title> should support dir attribute
        https://bugs.webkit.org/show_bug.cgi?id=50961

        Update to new FrameLoaderClient interface.

        * WebCoreSupport/FrameLoaderClientHaiku.cpp:
        (WebCore::FrameLoaderClientHaiku::dispatchDidReceiveTitle):
        * WebCoreSupport/FrameLoaderClientHaiku.h:
2011-03-31  Evan Martin  <evan@chromium.org>

        Reviewed by Eric Seidel.

        <title> should support dir attribute
        https://bugs.webkit.org/show_bug.cgi?id=50961

        Update to new FrameLoaderClient interface.

        * WebCoreSupport/WebFrameLoaderClient.h:
        * WebCoreSupport/WebFrameLoaderClient.mm:
        (WebFrameLoaderClient::dispatchDidReceiveTitle):
        (WebFrameLoaderClient::setTitle):
2011-03-31  Evan Martin  <evan@chromium.org>

        Reviewed by Eric Seidel.

        <title> should support dir attribute
        https://bugs.webkit.org/show_bug.cgi?id=50961

        Update to new FrameLoaderClient interface.

        * WebCoreSupport/FrameLoaderClientQt.cpp:
        (WebCore::FrameLoaderClientQt::dispatchDidReceiveTitle):
        (WebCore::FrameLoaderClientQt::setTitle):
        * WebCoreSupport/FrameLoaderClientQt.h:
2011-03-31  Evan Martin  <evan@chromium.org>

        Reviewed by Eric Seidel.

        <title> should support dir attribute
        https://bugs.webkit.org/show_bug.cgi?id=50961

        Update to new FrameLoaderClient interface.

        * WebCoreSupport/WebFrameLoaderClient.cpp:
        (WebFrameLoaderClient::dispatchDidReceiveTitle):
        * WebCoreSupport/WebFrameLoaderClient.h:
2011-03-31  Evan Martin  <evan@chromium.org>

        Reviewed by Eric Seidel.

        <title> should support dir attribute
        https://bugs.webkit.org/show_bug.cgi?id=50961

        Update to new FrameLoaderClient interface.

        * WebCoreSupport/FrameLoaderClientWinCE.cpp:
        (WebKit::FrameLoaderClientWinCE::dispatchDidReceiveTitle):
        (WebKit::FrameLoaderClientWinCE::setTitle):
        * WebCoreSupport/FrameLoaderClientWinCE.h:
2011-03-31  Evan Martin  <evan@chromium.org>

        Reviewed by Eric Seidel.

        <title> should support dir attribute
        https://bugs.webkit.org/show_bug.cgi?id=50961

        Update to new FrameLoaderClient interface.

        * WebKitSupport/FrameLoaderClientWx.cpp:
        (WebCore::FrameLoaderClientWx::dispatchDidReceiveTitle):
        (WebCore::FrameLoaderClientWx::setTitle):
        * WebKitSupport/FrameLoaderClientWx.h:
2011-03-31  Evan Martin  <evan@chromium.org>

        Reviewed by Eric Seidel.

        <title> should support dir attribute
        https://bugs.webkit.org/show_bug.cgi?id=50961

        Update to new FrameLoaderClient interface.

        * WebProcess/WebCoreSupport/WebFrameLoaderClient.cpp:
        (WebKit::WebFrameLoaderClient::dispatchDidReceiveTitle):
        (WebKit::WebFrameLoaderClient::setTitle):
        * WebProcess/WebCoreSupport/WebFrameLoaderClient.h:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@82580 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 9f08a12..1d50ded45 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,65 @@
+2011-03-31  Evan Martin  <evan@chromium.org>
+
+        Reviewed by Eric Seidel.
+
+        <title> should support dir attribute
+        https://bugs.webkit.org/show_bug.cgi?id=50961
+
+        Introduce a new StringWithDirection object that carries a String along
+        with the TextDirection associated with the String.  Use this object for
+        document titles used within WebCore, because in HTML the direction of
+        a title can be set with the 'dir' attribute.
+
+        Put FIXMEs at the WebKit level to expose the new direction information
+        to clients.
+
+        No behavioral change intended, so no new tests.  A follow-up will expose
+        the title direction and hopefully can be accompanied by tests that
+        verify it is correct.
+
+        * dom/Document.cpp:
+        (WebCore::Document::Document):
+        (WebCore::Document::updateTitle):
+        (WebCore::Document::setTitle):
+        (WebCore::Document::removeTitle):
+        * dom/Document.h:
+        (WebCore::Document::title):
+        * html/HTMLTitleElement.cpp:
+        (WebCore::HTMLTitleElement::HTMLTitleElement):
+        (WebCore::HTMLTitleElement::childrenChanged):
+        (WebCore::HTMLTitleElement::text):
+        (WebCore::HTMLTitleElement::textWithDirection):
+        * html/HTMLTitleElement.h:
+        * loader/DocumentLoader.cpp:
+        (WebCore::DocumentLoader::setTitle):
+        * loader/DocumentLoader.h:
+        (WebCore::DocumentLoader::title):
+        * loader/EmptyClients.h:
+        (WebCore::EmptyFrameLoaderClient::dispatchDidReceiveTitle):
+        (WebCore::EmptyFrameLoaderClient::setTitle):
+        * loader/FrameLoader.cpp:
+        (WebCore::FrameLoader::receivedFirstData):
+        (WebCore::FrameLoader::commitProvisionalLoad):
+        (WebCore::FrameLoader::setTitle):
+        * loader/FrameLoader.h:
+        * loader/FrameLoaderClient.h:
+        * loader/HistoryController.cpp:
+        (WebCore::HistoryController::updateForBackForwardNavigation):
+        (WebCore::HistoryController::updateForReload):
+        (WebCore::HistoryController::updateForRedirectWithLockedBackForwardList):
+        (WebCore::HistoryController::updateForClientRedirect):
+        (WebCore::HistoryController::updateForCommit):
+        (WebCore::HistoryController::setCurrentItemTitle):
+        (WebCore::HistoryController::initializeItem):
+        * loader/HistoryController.h:
+        * platform/text/StringWithDirection.h: Added.
+        (WebCore::StringWithDirection::StringWithDirection):
+        (WebCore::StringWithDirection::operator==):
+        (WebCore::StringWithDirection::operator!=):
+        * svg/SVGTitleElement.cpp:
+        (WebCore::SVGTitleElement::insertedIntoDocument):
+        (WebCore::SVGTitleElement::childrenChanged):
+
 2011-03-31  Alexander Pavlov  <apavlov@chromium.org>
 
         Reviewed by Yury Semikhatsky.
diff --git a/Source/WebCore/GNUmakefile.am b/Source/WebCore/GNUmakefile.am
index e2c49b4..88a1f07b 100644
--- a/Source/WebCore/GNUmakefile.am
+++ b/Source/WebCore/GNUmakefile.am
@@ -2689,6 +2689,7 @@
 	Source/WebCore/platform/text/SegmentedString.cpp \
 	Source/WebCore/platform/text/SegmentedString.h \
 	Source/WebCore/platform/text/String.cpp \
+	Source/WebCore/platform/text/StringWithDirection.h \
 	Source/WebCore/platform/text/SuffixTree.h \
 	Source/WebCore/platform/text/TextBoundaries.cpp \
 	Source/WebCore/platform/text/TextBoundaries.h \
diff --git a/Source/WebCore/WebCore.exp.in b/Source/WebCore/WebCore.exp.in
index f43cd5b..1b2a9c2 100644
--- a/Source/WebCore/WebCore.exp.in
+++ b/Source/WebCore/WebCore.exp.in
@@ -341,7 +341,7 @@
 __ZN7WebCore14DocumentLoader24removePlugInStreamLoaderEPNS_14ResourceLoaderE
 __ZN7WebCore14DocumentLoader7requestEv
 __ZN7WebCore14DocumentLoader8setFrameEPNS_5FrameE
-__ZN7WebCore14DocumentLoader8setTitleERKN3WTF6StringE
+__ZN7WebCore14DocumentLoader8setTitleERKNS_19StringWithDirectionE
 __ZN7WebCore14DocumentLoaderC1ERKNS_15ResourceRequestERKNS_14SubstituteDataE
 __ZN7WebCore14DocumentLoaderC2ERKNS_15ResourceRequestERKNS_14SubstituteDataE
 __ZN7WebCore14DocumentLoaderD2Ev
diff --git a/Source/WebCore/WebCore.gypi b/Source/WebCore/WebCore.gypi
index 87cefa3..ef071dc 100644
--- a/Source/WebCore/WebCore.gypi
+++ b/Source/WebCore/WebCore.gypi
@@ -4844,6 +4844,7 @@
             'platform/text/RegularExpression.cpp',
             'platform/text/SegmentedString.cpp',
             'platform/text/String.cpp',
+            'platform/text/StringWithDirection.h',
             'platform/text/SuffixTree.h',
             'platform/text/TextBoundaries.cpp',
             'platform/text/TextBreakIteratorICU.cpp',
diff --git a/Source/WebCore/WebCore.vcproj/WebCore.vcproj b/Source/WebCore/WebCore.vcproj/WebCore.vcproj
index afdb455..edb7079 100755
--- a/Source/WebCore/WebCore.vcproj/WebCore.vcproj
+++ b/Source/WebCore/WebCore.vcproj/WebCore.vcproj
@@ -30533,6 +30533,10 @@
 					>
 				</File>
 				<File
+					RelativePath="..\platform\text\StringWithDirection.h"
+					>
+				</File>
+				<File
 					RelativePath="..\platform\text\SuffixTree.h"
 					>
 				</File>
diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
index fe182f0..8a7ec17 100644
--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj
+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj
@@ -3130,6 +3130,7 @@
 		98EB1F951313FE0500D0E1EA /* NotImplemented.h in Headers */ = {isa = PBXBuildFile; fileRef = 98EB1F941313FE0500D0E1EA /* NotImplemented.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		9B417064125662B3006B28FC /* ApplyBlockElementCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B417062125662B3006B28FC /* ApplyBlockElementCommand.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		9B417065125662B3006B28FC /* ApplyBlockElementCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9B417063125662B3006B28FC /* ApplyBlockElementCommand.cpp */; };
+		9B6C41531344949000085B62 /* StringWithDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 9B6C41521344949000085B62 /* StringWithDirection.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		9BAB6C6C12550631001626D4 /* EditingStyle.h in Headers */ = {isa = PBXBuildFile; fileRef = 9BAB6C6A12550631001626D4 /* EditingStyle.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		9BAB6C6D12550631001626D4 /* EditingStyle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9BAB6C6B12550631001626D4 /* EditingStyle.cpp */; };
 		9BAF3B2412C1A39800014BF1 /* WritingDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 9BAF3B2312C1A39800014BF1 /* WritingDirection.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -9632,6 +9633,7 @@
 		98EB1F941313FE0500D0E1EA /* NotImplemented.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NotImplemented.h; sourceTree = "<group>"; };
 		9B417062125662B3006B28FC /* ApplyBlockElementCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplyBlockElementCommand.h; sourceTree = "<group>"; };
 		9B417063125662B3006B28FC /* ApplyBlockElementCommand.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ApplyBlockElementCommand.cpp; sourceTree = "<group>"; };
+		9B6C41521344949000085B62 /* StringWithDirection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringWithDirection.h; sourceTree = "<group>"; };
 		9BAB6C6A12550631001626D4 /* EditingStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditingStyle.h; sourceTree = "<group>"; };
 		9BAB6C6B12550631001626D4 /* EditingStyle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EditingStyle.cpp; sourceTree = "<group>"; };
 		9BAF3B2312C1A39800014BF1 /* WritingDirection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WritingDirection.h; sourceTree = "<group>"; };
@@ -17801,6 +17803,7 @@
 				B2C3D9FE0D006C1D00EF6F26 /* SegmentedString.cpp */,
 				B2C3D9FF0D006C1D00EF6F26 /* SegmentedString.h */,
 				B2C3DA000D006C1D00EF6F26 /* String.cpp */,
+				9B6C41521344949000085B62 /* StringWithDirection.h */,
 				97C0784F1165D5BE003A32EF /* SuffixTree.h */,
 				372C00C3129611F1005C9575 /* TextBoundaries.cpp */,
 				B2C3DA040D006C1D00EF6F26 /* TextBoundaries.h */,
@@ -22261,6 +22264,7 @@
 				3AB02D2A12D4F91600FBB694 /* StorageTracker.h in Headers */,
 				3AC3680012EF7A09006A3D6F /* StorageTrackerClient.h in Headers */,
 				81AC6C36131C57D30009A7E0 /* StringCallback.h in Headers */,
+				9B6C41531344949000085B62 /* StringWithDirection.h in Headers */,
 				65488D6B0DD5A83D009D83B2 /* StringSourceProvider.h in Headers */,
 				B23540F30D00782E002382FA /* StringTruncator.h in Headers */,
 				849F77760EFEC6200090849D /* StrokeStyleApplier.h in Headers */,
diff --git a/Source/WebCore/dom/Document.cpp b/Source/WebCore/dom/Document.cpp
index e3d7f53..5144703 100644
--- a/Source/WebCore/dom/Document.cpp
+++ b/Source/WebCore/dom/Document.cpp
@@ -389,8 +389,6 @@
     , m_containsValidityStyleRules(false)
     , m_updateFocusAppearanceRestoresSelection(false)
     , m_ignoreDestructiveWriteCount(0)
-    , m_title("")
-    , m_rawTitle("")
     , m_titleSetExplicitly(false)
     , m_updateFocusAppearanceTimer(this, &Document::updateFocusAppearanceTimerFired)
     , m_startTime(currentTime())
@@ -1271,8 +1269,9 @@
  *  2. Trim leading and trailing spaces
  *  3. Collapse internal whitespace.
  */
-static inline String canonicalizedTitle(Document* document, const String& title)
+static inline StringWithDirection canonicalizedTitle(Document* document, const StringWithDirection& titleWithDirection)
 {
+    const String& title = titleWithDirection.string();
     const UChar* characters = title.characters();
     unsigned length = title.length();
     unsigned i;
@@ -1288,7 +1287,7 @@
     }
 
     if (i == length)
-        return "";
+        return StringWithDirection();
 
     // Replace control characters with spaces, and backslashes with currency symbols, and collapse whitespace.
     bool previousCharWasWS = false;
@@ -1313,17 +1312,17 @@
     }
 
     if (!builderIndex && buffer[builderIndex] == ' ')
-        return "";
+        return StringWithDirection();
 
     buffer.shrink(builderIndex + 1);
 
     // Replace the backslashes with currency symbols if the encoding requires it.
     document->displayBufferModifiedByEncoding(buffer.characters(), buffer.length());
     
-    return String::adopt(buffer);
+    return StringWithDirection(String::adopt(buffer), titleWithDirection.direction());
 }
 
-void Document::updateTitle(const String& title)
+void Document::updateTitle(const StringWithDirection& title)
 {
     if (m_rawTitle == title)
         return;
@@ -1349,16 +1348,17 @@
         }
     }
 
-    updateTitle(title);
+    // The DOM API has no method of specifying direction, so assume LTR.
+    updateTitle(StringWithDirection(title, LTR));
 
     if (m_titleElement) {
         ASSERT(m_titleElement->hasTagName(titleTag));
         if (m_titleElement->hasTagName(titleTag))
-            static_cast<HTMLTitleElement*>(m_titleElement.get())->setText(m_title);
+            static_cast<HTMLTitleElement*>(m_titleElement.get())->setText(title);
     }
 }
 
-void Document::setTitleElement(const String& title, Element* titleElement)
+void Document::setTitleElement(const StringWithDirection& title, Element* titleElement)
 {
     if (titleElement != m_titleElement) {
         if (m_titleElement || m_titleSetExplicitly)
@@ -1383,13 +1383,13 @@
         for (Node* e = headElement->firstChild(); e; e = e->nextSibling())
             if (e->hasTagName(titleTag)) {
                 HTMLTitleElement* titleElement = static_cast<HTMLTitleElement*>(e);
-                setTitleElement(titleElement->text(), titleElement);
+                setTitleElement(titleElement->textWithDirection(), titleElement);
                 break;
             }
     }
 
     if (!m_titleElement)
-        updateTitle("");
+        updateTitle(StringWithDirection());
 }
 
 String Document::nodeName() const
diff --git a/Source/WebCore/dom/Document.h b/Source/WebCore/dom/Document.h
index 05dfb76..8a83d59 100644
--- a/Source/WebCore/dom/Document.h
+++ b/Source/WebCore/dom/Document.h
@@ -37,6 +37,7 @@
 #include "DocumentTiming.h"
 #include "QualifiedName.h"
 #include "ScriptExecutionContext.h"
+#include "StringWithDirection.h"
 #include "Timer.h"
 #include "ViewportArguments.h"
 #include <wtf/FixedArray.h>
@@ -811,9 +812,11 @@
     // Returns 0 if this is the top level document.
     HTMLFrameOwnerElement* ownerElement() const;
 
-    String title() const { return m_title; }
+    // Used by DOM bindings; no direction known.
+    String title() const { return m_title.string(); }
     void setTitle(const String&);
-    void setTitleElement(const String& title, Element* titleElement);
+
+    void setTitleElement(const StringWithDirection&, Element* titleElement);
     void removeTitle(Element* titleElement);
 
     String cookie(ExceptionCode&) const;
@@ -1158,7 +1161,7 @@
 
     String encoding() const;
 
-    void updateTitle(const String& title);
+    void updateTitle(const StringWithDirection&);
     void updateFocusAppearanceTimerFired(Timer<Document>*);
     void updateBaseURL();
 
@@ -1295,8 +1298,8 @@
     // http://www.whatwg.org/specs/web-apps/current-work/#ignore-destructive-writes-counter
     unsigned m_ignoreDestructiveWriteCount;
 
-    String m_title;
-    String m_rawTitle;
+    StringWithDirection m_title;
+    StringWithDirection m_rawTitle;
     bool m_titleSetExplicitly;
     RefPtr<Element> m_titleElement;
 
diff --git a/Source/WebCore/html/HTMLTitleElement.cpp b/Source/WebCore/html/HTMLTitleElement.cpp
index 78c8b6a..b046c7b 100644
--- a/Source/WebCore/html/HTMLTitleElement.cpp
+++ b/Source/WebCore/html/HTMLTitleElement.cpp
@@ -25,6 +25,7 @@
 
 #include "Document.h"
 #include "HTMLNames.h"
+#include "RenderStyle.h"
 #include "Text.h"
 
 namespace WebCore {
@@ -33,7 +34,6 @@
 
 inline HTMLTitleElement::HTMLTitleElement(const QualifiedName& tagName, Document* document)
     : HTMLElement(tagName, document)
-    , m_title("")
 {
     ASSERT(hasTagName(titleTag));
 }
@@ -57,7 +57,7 @@
 
 void HTMLTitleElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
 {
-    m_title = text();
+    m_title = textWithDirection();
     if (inDocument())
         document()->setTitleElement(m_title, this);
     HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
@@ -71,10 +71,20 @@
         if (n->isTextNode())
             val += static_cast<Text*>(n)->data();
     }
-    
+
     return val;
 }
 
+StringWithDirection HTMLTitleElement::textWithDirection()
+{
+    TextDirection direction = LTR;
+    if (RenderStyle* style = computedStyle())
+        direction = style->direction();
+    else if (RefPtr<RenderStyle> style = styleForRenderer())
+        direction = style->direction();
+    return StringWithDirection(text(), direction);
+}
+
 void HTMLTitleElement::setText(const String &value)
 {
     ExceptionCode ec = 0;
diff --git a/Source/WebCore/html/HTMLTitleElement.h b/Source/WebCore/html/HTMLTitleElement.h
index 8b90f56..6920997 100644
--- a/Source/WebCore/html/HTMLTitleElement.h
+++ b/Source/WebCore/html/HTMLTitleElement.h
@@ -23,6 +23,7 @@
 #define HTMLTitleElement_h
 
 #include "HTMLElement.h"
+#include "StringWithDirection.h"
 
 namespace WebCore {
 
@@ -33,6 +34,8 @@
     String text() const;
     void setText(const String&);
 
+    StringWithDirection textWithDirection();
+
 private:
     HTMLTitleElement(const QualifiedName&, Document*);
 
@@ -40,7 +43,7 @@
     virtual void removedFromDocument();
     virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
 
-    String m_title;
+    StringWithDirection m_title;
 };
 
 } //namespace
diff --git a/Source/WebCore/loader/DocumentLoader.cpp b/Source/WebCore/loader/DocumentLoader.cpp
index 121045b..1437adc 100644
--- a/Source/WebCore/loader/DocumentLoader.cpp
+++ b/Source/WebCore/loader/DocumentLoader.cpp
@@ -649,7 +649,7 @@
     m_stopRecordingResponses = true;
 }
 
-void DocumentLoader::setTitle(const String& title)
+void DocumentLoader::setTitle(const StringWithDirection& title)
 {
     if (title.isEmpty())
         return;
diff --git a/Source/WebCore/loader/DocumentLoader.h b/Source/WebCore/loader/DocumentLoader.h
index 1f88272..c6f0bc5 100644
--- a/Source/WebCore/loader/DocumentLoader.h
+++ b/Source/WebCore/loader/DocumentLoader.h
@@ -36,6 +36,7 @@
 #include "ResourceError.h"
 #include "ResourceRequest.h"
 #include "ResourceResponse.h"
+#include "StringWithDirection.h"
 #include "SubstituteData.h"
 #include "Timer.h"
 #include <wtf/HashSet.h>
@@ -121,7 +122,7 @@
         bool wasOnloadHandled() { return m_wasOnloadHandled; }
         bool isLoadingInAPISense() const;
         void setPrimaryLoadComplete(bool);
-        void setTitle(const String&);
+        void setTitle(const StringWithDirection&);
         void setIconURL(const String&);
         const String& overrideEncoding() const { return m_overrideEncoding; }
 
@@ -168,7 +169,7 @@
         const ResourceRequest& lastCheckedRequest()  { return m_lastCheckedRequest; }
 
         void stopRecordingResponses();
-        const String& title() const { return m_pageTitle; }
+        const StringWithDirection& title() const { return m_pageTitle; }
         const String& iconURL() const { return m_pageIconURL; }
 
         KURL urlForHistory() const;
@@ -298,7 +299,7 @@
         bool m_isClientRedirect;
         bool m_wasOnloadHandled;
 
-        String m_pageTitle;
+        StringWithDirection m_pageTitle;
         String m_pageIconURL;
 
         String m_overrideEncoding;
diff --git a/Source/WebCore/loader/EmptyClients.h b/Source/WebCore/loader/EmptyClients.h
index 59fd897..6acf992 100644
--- a/Source/WebCore/loader/EmptyClients.h
+++ b/Source/WebCore/loader/EmptyClients.h
@@ -266,7 +266,7 @@
     virtual void dispatchWillClose() { }
     virtual void dispatchDidReceiveIcon() { }
     virtual void dispatchDidStartProvisionalLoad() { }
-    virtual void dispatchDidReceiveTitle(const String&) { }
+    virtual void dispatchDidReceiveTitle(const StringWithDirection&) { }
     virtual void dispatchDidChangeIcons() { }
     virtual void dispatchDidCommitLoad() { }
     virtual void dispatchDidFailProvisionalLoad(const ResourceError&) { }
@@ -334,7 +334,7 @@
     virtual void prepareForDataSourceReplacement() { }
 
     virtual PassRefPtr<DocumentLoader> createDocumentLoader(const ResourceRequest& request, const SubstituteData& substituteData) { return DocumentLoader::create(request, substituteData); }
-    virtual void setTitle(const String&, const KURL&) { }
+    virtual void setTitle(const StringWithDirection&, const KURL&) { }
 
     virtual String userAgent(const KURL&) { return ""; }
 
diff --git a/Source/WebCore/loader/FrameLoader.cpp b/Source/WebCore/loader/FrameLoader.cpp
index 347a41e..f1020e1 100644
--- a/Source/WebCore/loader/FrameLoader.cpp
+++ b/Source/WebCore/loader/FrameLoader.cpp
@@ -610,7 +610,7 @@
     dispatchDidClearWindowObjectsInAllWorlds();
     
     if (m_documentLoader) {
-        String ptitle = m_documentLoader->title();
+        StringWithDirection ptitle = m_documentLoader->title();
         // If we have a title let the WebView know about it.
         if (!ptitle.isNull())
             m_client->dispatchDidReceiveTitle(ptitle);
@@ -1924,9 +1924,9 @@
         dispatchDidCommitLoad();
 
         // If we have a title let the WebView know about it. 
-        String title = m_documentLoader->title();
-        if (!title.isNull()) 
-            m_client->dispatchDidReceiveTitle(title);         
+        StringWithDirection title = m_documentLoader->title();
+        if (!title.isNull())
+            m_client->dispatchDidReceiveTitle(title);
 
         checkCompleted();
     } else {        
@@ -3375,7 +3375,7 @@
 }
 #endif
 
-void FrameLoader::setTitle(const String& title)
+void FrameLoader::setTitle(const StringWithDirection& title)
 {
     documentLoader()->setTitle(title);
 }
diff --git a/Source/WebCore/loader/FrameLoader.h b/Source/WebCore/loader/FrameLoader.h
index 1fb9e3c..9062f21 100644
--- a/Source/WebCore/loader/FrameLoader.h
+++ b/Source/WebCore/loader/FrameLoader.h
@@ -78,6 +78,7 @@
 class SecurityOrigin;
 class SerializedScriptValue;
 class SharedBuffer;
+class StringWithDirection;
 class SubstituteData;
 class TextResourceDecoder;
 
@@ -282,7 +283,7 @@
 
     void cancelAndClear();
 
-    void setTitle(const String&);
+    void setTitle(const StringWithDirection&);
     void setIconURL(const String&);
 
     void commitProvisionalLoad();
diff --git a/Source/WebCore/loader/FrameLoaderClient.h b/Source/WebCore/loader/FrameLoaderClient.h
index 7d64912..d5d49ec 100644
--- a/Source/WebCore/loader/FrameLoaderClient.h
+++ b/Source/WebCore/loader/FrameLoaderClient.h
@@ -84,6 +84,7 @@
     class ResourceResponse;
     class SecurityOrigin;
     class SharedBuffer;
+    class StringWithDirection;
     class SubstituteData;
     class Widget;
 
@@ -139,7 +140,7 @@
         virtual void dispatchWillClose() = 0;
         virtual void dispatchDidReceiveIcon() = 0;
         virtual void dispatchDidStartProvisionalLoad() = 0;
-        virtual void dispatchDidReceiveTitle(const String& title) = 0;
+        virtual void dispatchDidReceiveTitle(const StringWithDirection&) = 0;
         virtual void dispatchDidChangeIcons() = 0;
         virtual void dispatchDidCommitLoad() = 0;
         virtual void dispatchDidFailProvisionalLoad(const ResourceError&) = 0;
@@ -227,7 +228,7 @@
         virtual void prepareForDataSourceReplacement() = 0;
 
         virtual PassRefPtr<DocumentLoader> createDocumentLoader(const ResourceRequest&, const SubstituteData&) = 0;
-        virtual void setTitle(const String& title, const KURL&) = 0;
+        virtual void setTitle(const StringWithDirection&, const KURL&) = 0;
 
         virtual String userAgent(const KURL&) = 0;
         
diff --git a/Source/WebCore/loader/HistoryController.cpp b/Source/WebCore/loader/HistoryController.cpp
index b8bece9..c1c5414 100644
--- a/Source/WebCore/loader/HistoryController.cpp
+++ b/Source/WebCore/loader/HistoryController.cpp
@@ -265,7 +265,7 @@
 {
 #if !LOG_DISABLED
     if (m_frame->loader()->documentLoader())
-        LOG(History, "WebCoreHistory: Updating History for back/forward navigation in frame %s", m_frame->loader()->documentLoader()->title().utf8().data());
+        LOG(History, "WebCoreHistory: Updating History for back/forward navigation in frame %s", m_frame->loader()->documentLoader()->title().string().utf8().data());
 #endif
 
     // Must grab the current scroll position before disturbing it
@@ -281,7 +281,7 @@
 {
 #if !LOG_DISABLED
     if (m_frame->loader()->documentLoader())
-        LOG(History, "WebCoreHistory: Updating History for reload in frame %s", m_frame->loader()->documentLoader()->title().utf8().data());
+        LOG(History, "WebCoreHistory: Updating History for reload in frame %s", m_frame->loader()->documentLoader()->title().string().utf8().data());
 #endif
 
     if (m_currentItem) {
@@ -343,7 +343,7 @@
 {
 #if !LOG_DISABLED
     if (m_frame->loader()->documentLoader())
-        LOG(History, "WebCoreHistory: Updating History for redirect load in frame %s", m_frame->loader()->documentLoader()->title().utf8().data());
+        LOG(History, "WebCoreHistory: Updating History for redirect load in frame %s", m_frame->loader()->documentLoader()->title().string().utf8().data());
 #endif
     
     Settings* settings = m_frame->settings();
@@ -385,7 +385,7 @@
 {
 #if !LOG_DISABLED
     if (m_frame->loader()->documentLoader())
-        LOG(History, "WebCoreHistory: Updating History for client redirect in frame %s", m_frame->loader()->documentLoader()->title().utf8().data());
+        LOG(History, "WebCoreHistory: Updating History for client redirect in frame %s", m_frame->loader()->documentLoader()->title().string().utf8().data());
 #endif
 
     // Clear out form data so we don't try to restore it into the incoming page.  Must happen after
@@ -410,7 +410,7 @@
     FrameLoader* frameLoader = m_frame->loader();
 #if !LOG_DISABLED
     if (frameLoader->documentLoader())
-        LOG(History, "WebCoreHistory: Updating History for commit in frame %s", frameLoader->documentLoader()->title().utf8().data());
+        LOG(History, "WebCoreHistory: Updating History for commit in frame %s", frameLoader->documentLoader()->title().string().utf8().data());
 #endif
     FrameLoadType type = frameLoader->loadType();
     if (isBackForwardLoadType(type)
@@ -526,10 +526,11 @@
     m_currentItem = item;
 }
 
-void HistoryController::setCurrentItemTitle(const String& title)
+void HistoryController::setCurrentItemTitle(const StringWithDirection& title)
 {
     if (m_currentItem)
-        m_currentItem->setTitle(title);
+        // FIXME: make use of title.direction() as well.
+        m_currentItem->setTitle(title.string());
 }
 
 bool HistoryController::currentItemShouldBeReplaced() const
@@ -576,12 +577,13 @@
     
     Frame* parentFrame = m_frame->tree()->parent();
     String parent = parentFrame ? parentFrame->tree()->uniqueName() : "";
-    String title = documentLoader->title();
+    StringWithDirection title = documentLoader->title();
 
     item->setURL(url);
     item->setTarget(m_frame->tree()->uniqueName());
     item->setParent(parent);
-    item->setTitle(title);
+    // FIXME: should store title directionality in history as well.
+    item->setTitle(title.string());
     item->setOriginalURLString(originalURL.string());
 
     if (!unreachableURL.isEmpty() || documentLoader->response().httpStatusCode() >= 400)
diff --git a/Source/WebCore/loader/HistoryController.h b/Source/WebCore/loader/HistoryController.h
index 59f11a2..15e12c0 100644
--- a/Source/WebCore/loader/HistoryController.h
+++ b/Source/WebCore/loader/HistoryController.h
@@ -40,6 +40,7 @@
 class Frame;
 class HistoryItem;
 class SerializedScriptValue;
+class StringWithDirection;
 
 class HistoryController {
     WTF_MAKE_NONCOPYABLE(HistoryController);
@@ -71,7 +72,7 @@
 
     HistoryItem* currentItem() const { return m_currentItem.get(); }
     void setCurrentItem(HistoryItem*);
-    void setCurrentItemTitle(const String&);
+    void setCurrentItemTitle(const StringWithDirection&);
     bool currentItemShouldBeReplaced() const;
 
     HistoryItem* previousItem() const { return m_previousItem.get(); }
diff --git a/Source/WebCore/platform/text/StringWithDirection.h b/Source/WebCore/platform/text/StringWithDirection.h
new file mode 100644
index 0000000..ea34ab6
--- /dev/null
+++ b/Source/WebCore/platform/text/StringWithDirection.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef StringWithDirection_h
+#define StringWithDirection_h
+
+#include "PlatformString.h"
+#include "TextDirection.h"
+
+namespace WebCore {
+
+// In some circumstances we want to store a String along with the TextDirection
+// of the String as learned from the context of the String. For example,
+// consider storing the title derived from <title dir='rtl'>some title</title>
+// in the history.
+//
+// Note that is explicitly *not* the direction of the string as learned
+// from the characters of the string; it's extra metadata we have external
+// to the string.
+class StringWithDirection {
+public:
+    StringWithDirection() {}
+    StringWithDirection(const String& string, TextDirection dir) : m_string(string), m_direction(dir) {}
+
+    const String& string() const { return m_string; }
+    TextDirection direction() const { return m_direction; }
+
+    bool isEmpty() const { return m_string.isEmpty(); }
+    bool isNull() const { return m_string.isNull(); }
+
+    bool operator==(const StringWithDirection& other) const
+    {
+        return other.m_string == m_string && other.m_direction == m_direction;
+    }
+    bool operator!=(const StringWithDirection& other) const { return !((*this) == other); }
+
+private:
+    String m_string;
+    TextDirection m_direction;
+};
+
+}
+
+#endif // StringWithDirection_h
diff --git a/Source/WebCore/svg/SVGTitleElement.cpp b/Source/WebCore/svg/SVGTitleElement.cpp
index ebcddb4..d925603 100644
--- a/Source/WebCore/svg/SVGTitleElement.cpp
+++ b/Source/WebCore/svg/SVGTitleElement.cpp
@@ -40,7 +40,8 @@
 {
     SVGStyledElement::insertedIntoDocument();
     if (firstChild())
-        document()->setTitleElement(textContent(), this);
+        // FIXME: does SVG have a title text direction?
+        document()->setTitleElement(StringWithDirection(textContent(), LTR), this);
 }
 
 void SVGTitleElement::removedFromDocument()
@@ -53,7 +54,8 @@
 {
     SVGElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
     if (inDocument())
-        document()->setTitleElement(textContent(), this);
+        // FIXME: does SVG have title text direction?
+        document()->setTitleElement(StringWithDirection(textContent(), LTR), this);
 }
 
 AttributeToPropertyTypeMap& SVGTitleElement::attributeToPropertyTypeMap()