<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[173670] trunk/Source/WebCore</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/173670">173670</a></dd>
<dt>Author</dt> <dd>enrica@apple.com</dd>
<dt>Date</dt> <dd>2014-09-16 14:00:53 -0700 (Tue, 16 Sep 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Move HTMLConverter from editing/cocoa to platform/cocoa.
https://bugs.webkit.org/show_bug.cgi?id=136474

Reviewed by Benjamin Poulain.

This is a platform specific class and it belongs to the platform folder.

* WebCore.xcodeproj/project.pbxproj:
* editing/cocoa: Removed.
* editing/cocoa/HTMLConverter.h: Removed.
* editing/cocoa/HTMLConverter.mm: Removed.
* platform/cocoa/HTMLConverter.h: Copied from editing/cocoa/HTMLConverter.h.
* platform/cocoa/HTMLConverter.mm: Copied from editing/cocoa/HTMLConverter.mm.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreWebCorexcodeprojprojectpbxproj">trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreplatformcocoaHTMLConverterh">trunk/Source/WebCore/platform/cocoa/HTMLConverter.h</a></li>
<li><a href="#trunkSourceWebCoreplatformcocoaHTMLConvertermm">trunk/Source/WebCore/platform/cocoa/HTMLConverter.mm</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li>trunk/Source/WebCore/editing/cocoa/</li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (173669 => 173670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-09-16 20:38:46 UTC (rev 173669)
+++ trunk/Source/WebCore/ChangeLog        2014-09-16 21:00:53 UTC (rev 173670)
</span><span class="lines">@@ -1,5 +1,21 @@
</span><span class="cx"> 2014-09-16  Enrica Casucci  &lt;enrica@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        Move HTMLConverter from editing/cocoa to platform/cocoa.
+        https://bugs.webkit.org/show_bug.cgi?id=136474
+
+        Reviewed by Benjamin Poulain.
+
+        This is a platform specific class and it belongs to the platform folder.
+
+        * WebCore.xcodeproj/project.pbxproj:
+        * editing/cocoa: Removed.
+        * editing/cocoa/HTMLConverter.h: Removed.
+        * editing/cocoa/HTMLConverter.mm: Removed.
+        * platform/cocoa/HTMLConverter.h: Copied from editing/cocoa/HTMLConverter.h.
+        * platform/cocoa/HTMLConverter.mm: Copied from editing/cocoa/HTMLConverter.mm.
+
+2014-09-16  Enrica Casucci  &lt;enrica@apple.com&gt;
+
</ins><span class="cx">         Remove PLATFORM(IOS) from WebCore/editing (Part 3).
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=136474
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (173669 => 173670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2014-09-16 20:38:46 UTC (rev 173669)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2014-09-16 21:00:53 UTC (rev 173670)
</span><span class="lines">@@ -2382,8 +2382,6 @@
</span><span class="cx">                 7C2BDD3E17C7F98C0038FF15 /* JSDOMGlobalObjectTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C2BDD3C17C7F98B0038FF15 /* JSDOMGlobalObjectTask.h */; };
</span><span class="cx">                 7C3B79711908757B00B47A2D /* UserMessageHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C3B796F1908757B00B47A2D /* UserMessageHandler.cpp */; };
</span><span class="cx">                 7C3B79721908757B00B47A2D /* UserMessageHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C3B79701908757B00B47A2D /* UserMessageHandler.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><del>-                7C3E510A18DF8F3500C112F7 /* HTMLConverter.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C3E510818DF8F3500C112F7 /* HTMLConverter.h */; settings = {ATTRIBUTES = (Private, ); }; };
-                7C3E510B18DF8F3500C112F7 /* HTMLConverter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 7C3E510918DF8F3500C112F7 /* HTMLConverter.mm */; };
</del><span class="cx">                 7C48A6D0191C9D6500026674 /* WebKitNamespace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C48A6CE191C9D6500026674 /* WebKitNamespace.cpp */; };
</span><span class="cx">                 7C48A6D1191C9D6500026674 /* WebKitNamespace.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C48A6CF191C9D6500026674 /* WebKitNamespace.h */; };
</span><span class="cx">                 7C4902A218B825F8007D9298 /* DOMWheelEventInternal.h in Copy Generated Headers */ = {isa = PBXBuildFile; fileRef = 85989DCA0ACC8BBD00A0BC51 /* DOMWheelEventInternal.h */; };
</span><span class="lines">@@ -5528,6 +5526,8 @@
</span><span class="cx">                 C55C7BA11718AFBA001327E4 /* RenderThemeIOS.mm in Sources */ = {isa = PBXBuildFile; fileRef = C55C7BA01718AFBA001327E4 /* RenderThemeIOS.mm */; };
</span><span class="cx">                 C55E38BF10040D5D00A56BDB /* StorageNamespaceImpl.h in Headers */ = {isa = PBXBuildFile; fileRef = C55E38BB10040D5D00A56BDB /* StorageNamespaceImpl.h */; };
</span><span class="cx">                 C55E38C010040D5D00A56BDB /* StorageNamespaceImpl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C55E38BC10040D5D00A56BDB /* StorageNamespaceImpl.cpp */; };
</span><ins>+                C564FA7819C8D85C00488CAC /* HTMLConverter.h in Headers */ = {isa = PBXBuildFile; fileRef = C564FA7619C8D85C00488CAC /* HTMLConverter.h */; };
+                C564FA7919C8D85C00488CAC /* HTMLConverter.mm in Sources */ = {isa = PBXBuildFile; fileRef = C564FA7719C8D85C00488CAC /* HTMLConverter.mm */; };
</ins><span class="cx">                 C572EE1F1201C9BC007D8F82 /* JSIDBIndex.h in Headers */ = {isa = PBXBuildFile; fileRef = C572EE1D1201C9BC007D8F82 /* JSIDBIndex.h */; };
</span><span class="cx">                 C57FEDE11212EE9C0097BE65 /* FileSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C57FEDE01212EE9C0097BE65 /* FileSystem.cpp */; };
</span><span class="cx">                 C58361A91744523F00173511 /* FontServicesIOS.h in Headers */ = {isa = PBXBuildFile; fileRef = C58361A71744523F00173511 /* FontServicesIOS.h */; };
</span><span class="lines">@@ -9517,8 +9517,6 @@
</span><span class="cx">                 7C2BDD3C17C7F98B0038FF15 /* JSDOMGlobalObjectTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDOMGlobalObjectTask.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 7C3B796F1908757B00B47A2D /* UserMessageHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = UserMessageHandler.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 7C3B79701908757B00B47A2D /* UserMessageHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserMessageHandler.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><del>-                7C3E510818DF8F3500C112F7 /* HTMLConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLConverter.h; sourceTree = &quot;&lt;group&gt;&quot;; };
-                7C3E510918DF8F3500C112F7 /* HTMLConverter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = HTMLConverter.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</del><span class="cx">                 7C48A6CE191C9D6500026674 /* WebKitNamespace.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WebKitNamespace.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 7C48A6CF191C9D6500026674 /* WebKitNamespace.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebKitNamespace.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 7C48A6D2191C9D8E00026674 /* WebKitNamespace.idl */ = {isa = PBXFileReference; lastKnownFileType = text; path = WebKitNamespace.idl; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -12938,6 +12936,8 @@
</span><span class="cx">                 C55C7BA01718AFBA001327E4 /* RenderThemeIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RenderThemeIOS.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 C55E38BB10040D5D00A56BDB /* StorageNamespaceImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StorageNamespaceImpl.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 C55E38BC10040D5D00A56BDB /* StorageNamespaceImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StorageNamespaceImpl.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                C564FA7619C8D85C00488CAC /* HTMLConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLConverter.h; sourceTree = &quot;&lt;group&gt;&quot;; };
+                C564FA7719C8D85C00488CAC /* HTMLConverter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = HTMLConverter.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 C572EE1D1201C9BC007D8F82 /* JSIDBIndex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSIDBIndex.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 C57FEDE01212EE9C0097BE65 /* FileSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FileSystem.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 C58361A71744523F00173511 /* FontServicesIOS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FontServicesIOS.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -16674,15 +16674,6 @@
</span><span class="cx">                         tabWidth = 4;
</span><span class="cx">                         usesTabs = 0;
</span><span class="cx">                 };
</span><del>-                7C3E510718DF8F1200C112F7 /* cocoa */ = {
-                        isa = PBXGroup;
-                        children = (
-                                7C3E510818DF8F3500C112F7 /* HTMLConverter.h */,
-                                7C3E510918DF8F3500C112F7 /* HTMLConverter.mm */,
-                        );
-                        path = cocoa;
-                        sourceTree = &quot;&lt;group&gt;&quot;;
-                };
</del><span class="cx">                 7C74D43018823A4200E5ED57 /* icu */ = {
</span><span class="cx">                         isa = PBXGroup;
</span><span class="cx">                         children = (
</span><span class="lines">@@ -17334,7 +17325,6 @@
</span><span class="cx">                 93309D86099E64910056E581 /* editing */ = {
</span><span class="cx">                         isa = PBXGroup;
</span><span class="cx">                         children = (
</span><del>-                                7C3E510718DF8F1200C112F7 /* cocoa */,
</del><span class="cx">                                 443292C10EBA6D7300E62016 /* ios */,
</span><span class="cx">                                 ED501DC90B249F3900AE18D9 /* mac */,
</span><span class="cx">                                 CE08C3CF152B599A0021B8C2 /* AlternativeTextController.cpp */,
</span><span class="lines">@@ -18493,6 +18483,8 @@
</span><span class="cx">                         children = (
</span><span class="cx">                                 5D8C4DBD1428222C0026CE72 /* DisplaySleepDisablerCocoa.cpp */,
</span><span class="cx">                                 5D8C4DBE1428222C0026CE72 /* DisplaySleepDisablerCocoa.h */,
</span><ins>+                                C564FA7619C8D85C00488CAC /* HTMLConverter.h */,
+                                C564FA7719C8D85C00488CAC /* HTMLConverter.mm */,
</ins><span class="cx">                                 A5C974CF11485FF10066F2AB /* KeyEventCocoa.h */,
</span><span class="cx">                                 A5C974D011485FF10066F2AB /* KeyEventCocoa.mm */,
</span><span class="cx">                                 ADB6B29718FB90240081963E /* MemoryPressureHandlerCocoa.mm */,
</span><span class="lines">@@ -23679,7 +23671,6 @@
</span><span class="cx">                                 FD06DFA6134A4DEF006F5D7D /* DefaultAudioDestinationNode.h in Headers */,
</span><span class="cx">                                 4167EBF6102962BA003D252A /* DefaultSharedWorkerRepository.h in Headers */,
</span><span class="cx">                                 1AF4CEEA18BC350100BC2D34 /* DefaultVisitedLinkStore.h in Headers */,
</span><del>-                                7C3E510A18DF8F3500C112F7 /* HTMLConverter.h in Headers */,
</del><span class="cx">                                 FD31602C12B0267600C1A359 /* DelayDSPKernel.h in Headers */,
</span><span class="cx">                                 FD31602E12B0267600C1A359 /* DelayNode.h in Headers */,
</span><span class="cx">                                 FD31603112B0267600C1A359 /* DelayProcessor.h in Headers */,
</span><span class="lines">@@ -24258,6 +24249,7 @@
</span><span class="cx">                                 C4CD629B18383766007EBAF1 /* FrameSnapshotting.h in Headers */,
</span><span class="cx">                                 65A21485097A3F5300B9050A /* FrameTree.h in Headers */,
</span><span class="cx">                                 65CBFEFA0974F607001DAC25 /* FrameView.h in Headers */,
</span><ins>+                                C564FA7819C8D85C00488CAC /* HTMLConverter.h in Headers */,
</ins><span class="cx">                                 97205AB0123928CA00B17380 /* FTPDirectoryDocument.h in Headers */,
</span><span class="cx">                                 51C81B8A0C4422F70019ECE3 /* FTPDirectoryParser.h in Headers */,
</span><span class="cx">                                 26B999931803B9D900D01121 /* FunctionCall.h in Headers */,
</span><span class="lines">@@ -28916,7 +28908,6 @@
</span><span class="cx">                                 31078CC71880AAB5008099DC /* OESTextureHalfFloatLinear.cpp in Sources */,
</span><span class="cx">                                 77A17A7112F28182004E02F6 /* OESVertexArrayObject.cpp in Sources */,
</span><span class="cx">                                 FDA3E959134A49EF008D4B5A /* OfflineAudioCompletionEvent.cpp in Sources */,
</span><del>-                                7C3E510B18DF8F3500C112F7 /* HTMLConverter.mm in Sources */,
</del><span class="cx">                                 FDA9325D16703B2A008982DC /* OfflineAudioContext.cpp in Sources */,
</span><span class="cx">                                 FDA3E95B134A49EF008D4B5A /* OfflineAudioDestinationNode.cpp in Sources */,
</span><span class="cx">                                 CDE7FC44181904B1002BBB77 /* OrderIterator.cpp in Sources */,
</span><span class="lines">@@ -29646,6 +29637,7 @@
</span><span class="cx">                                 071A9EC2168FBC43002629F9 /* TextTrackCueGeneric.cpp in Sources */,
</span><span class="cx">                                 9759E94514EF1CF80026A2DD /* TextTrackCueList.cpp in Sources */,
</span><span class="cx">                                 076970861463AD8700F502CF /* TextTrackList.cpp in Sources */,
</span><ins>+                                C564FA7919C8D85C00488CAC /* HTMLConverter.mm in Sources */,
</ins><span class="cx">                                 B1AD4E7313A12A4600846B27 /* TextTrackLoader.cpp in Sources */,
</span><span class="cx">                                 CD1E7347167BC78E009A885D /* TextTrackRepresentation.cpp in Sources */,
</span><span class="cx">                                 CDCA82961679100F00875714 /* TextTrackRepresentationIOS.mm in Sources */,
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformcocoaHTMLConverterhfromrev173664trunkSourceWebCoreeditingcocoaHTMLConverterh"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebCore/platform/cocoa/HTMLConverter.h (from rev 173664, trunk/Source/WebCore/editing/cocoa/HTMLConverter.h) (0 => 173670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/cocoa/HTMLConverter.h                                (rev 0)
+++ trunk/Source/WebCore/platform/cocoa/HTMLConverter.h        2014-09-16 21:00:53 UTC (rev 173670)
</span><span class="lines">@@ -0,0 +1,42 @@
</span><ins>+/*
+ * Copyright (C) 2010-2013 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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 HTMLConverter_h
+#define HTMLConverter_h
+
+OBJC_CLASS NSAttributedString;
+
+namespace WebCore {
+    
+class Range;
+    
+WEBCORE_EXPORT NSAttributedString *attributedStringFromRange(Range&amp;);
+#if !PLATFORM(IOS)
+WEBCORE_EXPORT NSAttributedString *editingAttributedStringFromRange(Range&amp;);
+#endif
+
+}
+
+#endif // HTMLConverter_h
</ins></span></pre></div>
<a id="trunkSourceWebCoreplatformcocoaHTMLConvertermmfromrev173669trunkSourceWebCoreeditingcocoaHTMLConvertermm"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebCore/platform/cocoa/HTMLConverter.mm (from rev 173669, trunk/Source/WebCore/editing/cocoa/HTMLConverter.mm) (0 => 173670)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/cocoa/HTMLConverter.mm                                (rev 0)
+++ trunk/Source/WebCore/platform/cocoa/HTMLConverter.mm        2014-09-16 21:00:53 UTC (rev 173670)
</span><span class="lines">@@ -0,0 +1,2616 @@
</span><ins>+/*
+ * Copyright (C) 2011, 2012 Apple 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:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS 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 APPLE INC. OR ITS 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.
+ */
+
+#import &quot;config.h&quot;
+#import &quot;HTMLConverter.h&quot;
+
+#import &quot;ArchiveResource.h&quot;
+#import &quot;CSSComputedStyleDeclaration.h&quot;
+#import &quot;CSSParser.h&quot;
+#import &quot;CSSPrimitiveValue.h&quot;
+#import &quot;CachedImage.h&quot;
+#import &quot;CharacterData.h&quot;
+#import &quot;ColorMac.h&quot;
+#import &quot;Document.h&quot;
+#import &quot;DocumentLoader.h&quot;
+#import &quot;Element.h&quot;
+#import &quot;ElementTraversal.h&quot;
+#import &quot;Font.h&quot;
+#import &quot;Frame.h&quot;
+#import &quot;FrameLoader.h&quot;
+#import &quot;HTMLElement.h&quot;
+#import &quot;HTMLFrameElementBase.h&quot;
+#import &quot;HTMLInputElement.h&quot;
+#import &quot;HTMLMetaElement.h&quot;
+#import &quot;HTMLNames.h&quot;
+#import &quot;HTMLOListElement.h&quot;
+#import &quot;HTMLParserIdioms.h&quot;
+#import &quot;HTMLTableCellElement.h&quot;
+#import &quot;HTMLTextAreaElement.h&quot;
+#import &quot;LoaderNSURLExtras.h&quot;
+#import &quot;RGBColor.h&quot;
+#import &quot;RenderImage.h&quot;
+#import &quot;SoftLinking.h&quot;
+#import &quot;StyleProperties.h&quot;
+#import &quot;StyledElement.h&quot;
+#import &quot;TextIterator.h&quot;
+#import &lt;objc/runtime.h&gt;
+#import &lt;wtf/ASCIICType.h&gt;
+#import &lt;wtf/text/StringBuilder.h&gt;
+
+#if PLATFORM(IOS)
+
+#import &quot;WAKAppKitStubs.h&quot;
+
+SOFT_LINK_FRAMEWORK(UIKit)
+SOFT_LINK_CLASS(UIKit, UIColor)
+
+SOFT_LINK_PRIVATE_FRAMEWORK(UIFoundation)
+SOFT_LINK_CLASS(UIFoundation, UIFont)
+SOFT_LINK_CLASS(UIFoundation, NSColor)
+SOFT_LINK_CLASS(UIFoundation, NSShadow)
+SOFT_LINK_CLASS(UIFoundation, NSTextAttachment)
+SOFT_LINK_CLASS(UIFoundation, NSMutableParagraphStyle)
+SOFT_LINK_CLASS(UIFoundation, NSParagraphStyle)
+SOFT_LINK_CLASS(UIFoundation, NSTextList)
+SOFT_LINK_CLASS(UIFoundation, NSTextBlock)
+SOFT_LINK_CLASS(UIFoundation, NSTextTableBlock)
+SOFT_LINK_CLASS(UIFoundation, NSTextTable)
+SOFT_LINK_CLASS(UIFoundation, NSTextTab)
+
+SOFT_LINK_CONSTANT(UIFoundation, NSFontAttributeName, NSString *)
+#define NSFontAttributeName getNSFontAttributeName()
+SOFT_LINK_CONSTANT(UIFoundation, NSForegroundColorAttributeName, NSString *)
+#define NSForegroundColorAttributeName getNSForegroundColorAttributeName()
+SOFT_LINK_CONSTANT(UIFoundation, NSBackgroundColorAttributeName, NSString *)
+#define NSBackgroundColorAttributeName getNSBackgroundColorAttributeName()
+SOFT_LINK_CONSTANT(UIFoundation, NSStrokeColorAttributeName, NSString *)
+#define NSStrokeColorAttributeName getNSStrokeColorAttributeName()
+SOFT_LINK_CONSTANT(UIFoundation, NSStrokeWidthAttributeName, NSString *)
+#define NSStrokeWidthAttributeName getNSStrokeWidthAttributeName()
+SOFT_LINK_CONSTANT(UIFoundation, NSShadowAttributeName, NSString *)
+#define NSShadowAttributeName getNSShadowAttributeName()
+SOFT_LINK_CONSTANT(UIFoundation, NSKernAttributeName, NSString *)
+#define NSKernAttributeName getNSKernAttributeName()
+SOFT_LINK_CONSTANT(UIFoundation, NSLigatureAttributeName, NSString *)
+#define NSLigatureAttributeName getNSLigatureAttributeName()
+SOFT_LINK_CONSTANT(UIFoundation, NSUnderlineStyleAttributeName, NSString *)
+#define NSUnderlineStyleAttributeName getNSUnderlineStyleAttributeName()
+SOFT_LINK_CONSTANT(UIFoundation, NSStrikethroughStyleAttributeName, NSString *)
+#define NSStrikethroughStyleAttributeName getNSStrikethroughStyleAttributeName()
+SOFT_LINK_CONSTANT(UIFoundation, NSBaselineOffsetAttributeName, NSString *)
+#define NSBaselineOffsetAttributeName getNSBaselineOffsetAttributeName()
+SOFT_LINK_CONSTANT(UIFoundation, NSWritingDirectionAttributeName, NSString *)
+#define NSWritingDirectionAttributeName getNSWritingDirectionAttributeName()
+SOFT_LINK_CONSTANT(UIFoundation, NSParagraphStyleAttributeName, NSString *)
+#define NSParagraphStyleAttributeName getNSParagraphStyleAttributeName()
+SOFT_LINK_CONSTANT(UIFoundation, NSAttachmentAttributeName, NSString *)
+#define NSAttachmentAttributeName getNSAttachmentAttributeName()
+SOFT_LINK_CONSTANT(UIFoundation, NSLinkAttributeName, NSString *)
+#define NSLinkAttributeName getNSLinkAttributeName()
+SOFT_LINK_CONSTANT(UIFoundation, NSAuthorDocumentAttribute, NSString *)
+#define NSAuthorDocumentAttribute getNSAuthorDocumentAttribute()
+SOFT_LINK_CONSTANT(UIFoundation, NSEditorDocumentAttribute, NSString *)
+#define NSEditorDocumentAttribute getNSEditorDocumentAttribute()
+SOFT_LINK_CONSTANT(UIFoundation, NSGeneratorDocumentAttribute, NSString *)
+#define NSGeneratorDocumentAttribute getNSGeneratorDocumentAttribute()
+SOFT_LINK_CONSTANT(UIFoundation, NSCompanyDocumentAttribute, NSString *)
+#define NSCompanyDocumentAttribute getNSCompanyDocumentAttribute()
+SOFT_LINK_CONSTANT(UIFoundation, NSDisplayNameDocumentAttribute, NSString *)
+#define NSDisplayNameDocumentAttribute getNSDisplayNameDocumentAttribute()
+SOFT_LINK_CONSTANT(UIFoundation, NSCopyrightDocumentAttribute, NSString *)
+#define NSCopyrightDocumentAttribute getNSCopyrightDocumentAttribute()
+SOFT_LINK_CONSTANT(UIFoundation, NSSubjectDocumentAttribute, NSString *)
+#define NSSubjectDocumentAttribute getNSSubjectDocumentAttribute()
+SOFT_LINK_CONSTANT(UIFoundation, NSCommentDocumentAttribute, NSString *)
+#define NSCommentDocumentAttribute getNSCommentDocumentAttribute()
+SOFT_LINK_CONSTANT(UIFoundation, NSNoIndexDocumentAttribute, NSString *)
+#define NSNoIndexDocumentAttribute getNSNoIndexDocumentAttribute()
+SOFT_LINK_CONSTANT(UIFoundation, NSKeywordsDocumentAttribute, NSString *)
+#define NSKeywordsDocumentAttribute getNSKeywordsDocumentAttribute()
+SOFT_LINK_CONSTANT(UIFoundation, NSCreationTimeDocumentAttribute, NSString *)
+#define NSCreationTimeDocumentAttribute getNSCreationTimeDocumentAttribute()
+SOFT_LINK_CONSTANT(UIFoundation, NSModificationTimeDocumentAttribute, NSString *)
+#define NSModificationTimeDocumentAttribute getNSModificationTimeDocumentAttribute()
+SOFT_LINK_CONSTANT(UIFoundation, NSConvertedDocumentAttribute, NSString *)
+#define NSConvertedDocumentAttribute getNSConvertedDocumentAttribute()
+SOFT_LINK_CONSTANT(UIFoundation, NSCocoaVersionDocumentAttribute, NSString *)
+#define NSCocoaVersionDocumentAttribute getNSCocoaVersionDocumentAttribute()
+
+#define PlatformNSShadow            getNSShadowClass()
+#define PlatformNSTextAttachment    getNSTextAttachmentClass()
+#define PlatformNSParagraphStyle    getNSParagraphStyleClass()
+#define PlatformNSTextList          getNSTextListClass()
+#define PlatformNSTextTableBlock    getNSTextTableBlockClass()
+#define PlatformNSTextTable         getNSTextTableClass()
+#define PlatformNSTextTab           getNSTextTabClass()
+#define PlatformColor               UIColor
+#define PlatformColorClass          getUIColorClass()
+#define PlatformNSColorClass        getNSColorClass()
+#define PlatformFont                UIFont
+#define PlatformFontClass           getUIFontClass()
+
+// We don't softlink NSSuperscriptAttributeName because UIFoundation stopped exporting it.
+// This attribute is being deprecated at the API level, but internally UIFoundation
+// will continue to support it.
+static NSString *const NSSuperscriptAttributeName = @&quot;NSSuperscript&quot;;
+#else
+
+#define PlatformNSShadow            NSShadow
+#define PlatformNSTextAttachment    NSTextAttachment
+#define PlatformNSParagraphStyle    NSParagraphStyle
+#define PlatformNSTextList          NSTextList
+#define PlatformNSTextTableBlock    NSTextTableBlock
+#define PlatformNSTextTable         NSTextTable
+#define PlatformNSTextTab           NSTextTab
+#define PlatformColor               NSColor
+#define PlatformColorClass          NSColor
+#define PlatformNSColorClass        NSColor
+#define PlatformFont                NSFont
+#define PlatformFontClass           NSFont
+
+#define NSTextAlignmentLeft         NSLeftTextAlignment
+#define NSTextAlignmentRight        NSRightTextAlignment
+#define NSTextAlignmentCenter       NSCenterTextAlignment
+#define NSTextAlignmentJustified    NSJustifiedTextAlignment
+#endif
+
+using namespace WebCore;
+using namespace HTMLNames;
+
+#if PLATFORM(IOS)
+
+typedef enum {
+    UIFontTraitPlain       = 0x00000000,
+    UIFontTraitItalic      = 0x00000001, // 1 &lt;&lt; 0
+    UIFontTraitBold        = 0x00000002, // 1 &lt;&lt; 1
+    UIFontTraitThin        = (1 &lt;&lt; 2),
+    UIFontTraitLight       = (1 &lt;&lt; 3),
+    UIFontTraitUltraLight  = (1 &lt;&lt; 4)
+} UIFontTrait;
+
+typedef NS_ENUM(NSInteger, NSUnderlineStyle) {
+    NSUnderlineStyleNone                                = 0x00,
+    NSUnderlineStyleSingle                              = 0x01,
+    NSUnderlineStyleThick NS_ENUM_AVAILABLE_IOS(7_0)    = 0x02,
+    NSUnderlineStyleDouble NS_ENUM_AVAILABLE_IOS(7_0)   = 0x09,
+
+    NSUnderlinePatternSolid NS_ENUM_AVAILABLE_IOS(7_0)      = 0x0000,
+    NSUnderlinePatternDot NS_ENUM_AVAILABLE_IOS(7_0)        = 0x0100,
+    NSUnderlinePatternDash NS_ENUM_AVAILABLE_IOS(7_0)       = 0x0200,
+    NSUnderlinePatternDashDot NS_ENUM_AVAILABLE_IOS(7_0)    = 0x0300,
+    NSUnderlinePatternDashDotDot NS_ENUM_AVAILABLE_IOS(7_0) = 0x0400,
+
+    NSUnderlineByWord NS_ENUM_AVAILABLE_IOS(7_0) = 0x8000
+};
+
+enum {
+    NSTextBlockAbsoluteValueType    = 0,    // Absolute value in points
+    NSTextBlockPercentageValueType  = 1     // Percentage value (out of 100)
+};
+typedef NSUInteger NSTextBlockValueType;
+
+enum {
+    NSTextBlockWidth            = 0,
+    NSTextBlockMinimumWidth     = 1,
+    NSTextBlockMaximumWidth     = 2,
+    NSTextBlockHeight           = 4,
+    NSTextBlockMinimumHeight    = 5,
+    NSTextBlockMaximumHeight    = 6
+};
+typedef NSUInteger NSTextBlockDimension;
+
+enum {
+    NSTextBlockPadding  = -1,
+    NSTextBlockBorder   =  0,
+    NSTextBlockMargin   =  1
+};
+typedef NSInteger NSTextBlockLayer;
+
+enum {
+    NSTextTableAutomaticLayoutAlgorithm = 0,
+    NSTextTableFixedLayoutAlgorithm     = 1
+};
+typedef NSUInteger NSTextTableLayoutAlgorithm;
+
+enum {
+    NSTextBlockTopAlignment         = 0,
+    NSTextBlockMiddleAlignment      = 1,
+    NSTextBlockBottomAlignment      = 2,
+    NSTextBlockBaselineAlignment    = 3
+};
+typedef NSUInteger NSTextBlockVerticalAlignment;
+
+typedef NS_ENUM(NSInteger, NSTextAlignment) {
+    NSTextAlignmentLeft      = 0,    // Visually left aligned
+    NSTextAlignmentCenter    = 1,    // Visually centered
+    NSTextAlignmentRight     = 2,    // Visually right aligned
+    NSTextAlignmentJustified = 3,    // Fully-justified. The last line in a paragraph is natural-aligned.
+    NSTextAlignmentNatural   = 4,    // Indicates the default alignment for script
+} NS_ENUM_AVAILABLE_IOS(6_0);
+
+typedef NS_ENUM(NSInteger, NSWritingDirection) {
+    NSWritingDirectionNatural       = -1,    // Determines direction using the Unicode Bidi Algorithm rules P2 and P3
+    NSWritingDirectionLeftToRight   =  0,    // Left to right writing direction
+    NSWritingDirectionRightToLeft   =  1     // Right to left writing direction
+} NS_ENUM_AVAILABLE_IOS(6_0);
+
+typedef NS_ENUM(NSInteger, NSTextWritingDirection) {
+    NSTextWritingDirectionEmbedding     = (0 &lt;&lt; 1),
+    NSTextWritingDirectionOverride      = (1 &lt;&lt; 1)
+} NS_ENUM_AVAILABLE_IOS(7_0);
+
+enum {
+    NSEnterCharacter                = 0x0003,
+    NSBackspaceCharacter            = 0x0008,
+    NSTabCharacter                  = 0x0009,
+    NSNewlineCharacter              = 0x000a,
+    NSFormFeedCharacter             = 0x000c,
+    NSCarriageReturnCharacter       = 0x000d,
+    NSBackTabCharacter              = 0x0019,
+    NSDeleteCharacter               = 0x007f,
+    NSLineSeparatorCharacter        = 0x2028,
+    NSParagraphSeparatorCharacter   = 0x2029,
+    NSAttachmentCharacter           = 0xFFFC // Replacement character is used for attachments
+};
+
+enum {
+    NSLeftTabStopType = 0,
+    NSRightTabStopType,
+    NSCenterTabStopType,
+    NSDecimalTabStopType
+};
+typedef NSUInteger NSTextTabType;
+
+@interface UIColor : NSObject
++ (UIColor *)clearColor;
+- (CGFloat)alphaComponent;
++ (UIColor *)_disambiguated_due_to_CIImage_colorWithCGColor:(CGColorRef)cgColor;
+@end
+
+@interface NSColor : UIColor
++ (id)colorWithCalibratedRed:(CGFloat)red green:(CGFloat)green blue:(CGFloat)blue alpha:(CGFloat)alpha;
+@end
+
+@interface UIFont
++ (UIFont *)fontWithName:(NSString *)fontName size:(CGFloat)fontSize;
++ (UIFont *)fontWithFamilyName:(NSString *)familyName traits:(UIFontTrait)traits size:(CGFloat)fontSize;
+- (NSString *)familyName;
+- (CGFloat)pointSize;
+- (UIFont *)fontWithSize:(CGFloat)fontSize;
++ (NSArray *)familyNames;
++ (NSArray *)fontNamesForFamilyName:(NSString *)familyName;
++ (UIFont *)systemFontOfSize:(CGFloat)fontSize;
+@end
+
+@interface NSTextTab
+- (id)initWithType:(NSTextTabType)type location:(CGFloat)loc;
+- (id)initWithTextAlignment:(NSTextAlignment)alignment location:(CGFloat)loc options:(NSDictionary *)options;
+- (CGFloat)location;
+- (void)release;
+@end
+
+@interface NSParagraphStyle : NSObject
++ (NSParagraphStyle *)defaultParagraphStyle;
+- (void)setAlignment:(NSTextAlignment)alignment;
+- (void)setBaseWritingDirection:(NSWritingDirection)writingDirection;
+- (void)setHeadIndent:(CGFloat)aFloat;
+- (CGFloat)headIndent;
+- (void)setHeaderLevel:(NSInteger)level;
+- (void)setFirstLineHeadIndent:(CGFloat)aFloat;
+- (void)setTailIndent:(CGFloat)aFloat;
+- (void)setParagraphSpacing:(CGFloat)paragraphSpacing;
+- (void)setTextLists:(NSArray *)array;
+- (void)setTextBlocks:(NSArray *)array;
+- (void)setMinimumLineHeight:(CGFloat)aFloat;
+- (NSArray *)textLists;
+- (void)removeTabStop:(NSTextTab *)anObject;
+- (void)addTabStop:(NSTextTab *)anObject;
+- (NSArray *)tabStops;
+- (void)setHyphenationFactor:(float)aFactor;
+@end
+
+@interface NSShadow
+- (void)setShadowOffset:(CGSize)size;
+- (void)setShadowBlurRadius:(CGFloat)radius;
+- (void)setShadowColor:(UIColor *)color;
+@end
+
+@interface NSTextBlock : NSObject
+- (void)setValue:(CGFloat)val type:(NSTextBlockValueType)type forDimension:(NSTextBlockDimension)dimension;
+- (void)setWidth:(CGFloat)val type:(NSTextBlockValueType)type forLayer:(NSTextBlockLayer)layer edge:(NSRectEdge)edge;
+- (void)setBackgroundColor:(UIColor *)color;
+- (UIColor *)backgroundColor;
+- (void)setBorderColor:(UIColor *)color forEdge:(NSRectEdge)edge;
+- (void)setBorderColor:(UIColor *)color;        // Convenience method sets all edges at once
+- (void)setVerticalAlignment:(NSTextBlockVerticalAlignment)alignment;
+@end
+
+@interface NSTextList
+- (id)initWithMarkerFormat:(NSString *)format options:(NSUInteger)mask;
+- (void)setStartingItemNumber:(NSInteger)itemNum;
+- (NSInteger)startingItemNumber;
+- (NSString *)markerForItemNumber:(NSInteger)itemNum;
+- (void)release;
+@end
+
+@interface NSMutableParagraphStyle : NSParagraphStyle
+- (void)setDefaultTabInterval:(CGFloat)aFloat;
+- (void)setTabStops:(NSArray *)array;
+@end
+
+@interface NSTextAttachment : NSObject
+- (id)initWithFileWrapper:(NSFileWrapper *)fileWrapper;
+#if PLATFORM(IOS)
+- (void)setBounds:(CGRect)bounds;
+#endif
+- (void)release;
+@end
+
+@interface NSTextTable : NSTextBlock
+- (void)setNumberOfColumns:(NSUInteger)numCols;
+- (void)setCollapsesBorders:(BOOL)flag;
+- (void)setHidesEmptyCells:(BOOL)flag;
+- (void)setLayoutAlgorithm:(NSTextTableLayoutAlgorithm)algorithm;
+- (NSUInteger)numberOfColumns;
+- (void)release;
+@end
+
+@interface NSTextTableBlock : NSTextBlock
+- (id)initWithTable:(NSTextTable *)table startingRow:(NSInteger)row rowSpan:(NSInteger)rowSpan startingColumn:(NSInteger)col columnSpan:(NSInteger)colSpan;     // Designated initializer
+- (NSInteger)startingColumn;
+- (NSInteger)startingRow;
+- (NSUInteger)numberOfColumns;
+- (NSInteger)columnSpan;
+- (NSInteger)rowSpan;
+@end
+
+#else
+static NSFileWrapper *fileWrapperForURL(DocumentLoader *, NSURL *);
+static NSFileWrapper *fileWrapperForElement(Element*);
+
+@interface NSTextAttachment (WebCoreNSTextAttachment)
+- (void)setIgnoresOrientation:(BOOL)flag;
+- (void)setBounds:(CGRect)bounds;
+- (BOOL)ignoresOrientation;
+@end
+
+#endif
+
+// Additional control Unicode characters
+const unichar WebNextLineCharacter = 0x0085;
+
+static const CGFloat defaultFontSize = 12;
+static const CGFloat minimumFontSize = 1;
+
+class HTMLConverterCaches {
+public:
+    String propertyValueForNode(Node&amp;, CSSPropertyID );
+    bool floatPropertyValueForNode(Node&amp;, CSSPropertyID, float&amp;);
+    Color colorPropertyValueForNode(Node&amp;, CSSPropertyID);
+
+    bool isBlockElement(Element&amp;);
+    bool elementHasOwnBackgroundColor(Element&amp;);
+
+    PassRefPtr&lt;CSSValue&gt; computedStylePropertyForElement(Element&amp;, CSSPropertyID);
+    PassRefPtr&lt;CSSValue&gt; inlineStylePropertyForElement(Element&amp;, CSSPropertyID);
+
+    Node* cacheAncestorsOfStartToBeConverted(const Range&amp;);
+    bool isAncestorsOfStartToBeConverted(Node&amp; node) const { return m_ancestorsUnderCommonAncestor.contains(&amp;node); }
+
+private:
+    HashMap&lt;Element*, std::unique_ptr&lt;ComputedStyleExtractor&gt;&gt; m_computedStyles;
+    HashSet&lt;Node*&gt; m_ancestorsUnderCommonAncestor;
+};
+
+@interface NSTextList (WebCoreNSTextListDetails)
++ (NSDictionary *)_standardMarkerAttributesForAttributes:(NSDictionary *)attrs;
+@end
+
+@interface NSURL (WebCoreNSURLDetails)
+// FIXME: What is the reason to use this Foundation method, and not +[NSURL URLWithString:relativeToURL:]?
++ (NSURL *)_web_URLWithString:(NSString *)string relativeToURL:(NSURL *)baseURL;
+@end
+
+@interface NSObject(WebMessageDocumentSimulation)
++ (void)document:(NSObject **)outDocument attachment:(NSTextAttachment **)outAttachment forURL:(NSURL *)url;
+@end
+
+class HTMLConverter {
+public:
+    HTMLConverter(Range&amp;);
+    ~HTMLConverter();
+    
+    NSAttributedString* convert();
+    
+private:
+    Ref&lt;Range&gt; m_range;
+    DocumentLoader* m_dataSource;
+    
+    HashMap&lt;RefPtr&lt;Element&gt;, RetainPtr&lt;NSDictionary&gt;&gt; m_attributesForElements;
+    HashMap&lt;RetainPtr&lt;NSTextTable&gt;, RefPtr&lt;Element&gt;&gt; m_textTableFooters;
+    HashMap&lt;RefPtr&lt;Element&gt;, RetainPtr&lt;NSDictionary&gt;&gt; m_aggregatedAttributesForElements;
+
+    NSMutableAttributedString *_attrStr;
+    NSMutableDictionary *_documentAttrs;
+    NSURL *_baseURL;
+    NSMutableArray *_textLists;
+    NSMutableArray *_textBlocks;
+    NSMutableArray *_textTables;
+    NSMutableArray *_textTableSpacings;
+    NSMutableArray *_textTablePaddings;
+    NSMutableArray *_textTableRows;
+    NSMutableArray *_textTableRowArrays;
+    NSMutableArray *_textTableRowBackgroundColors;
+    NSMutableDictionary *_fontCache;
+    NSMutableArray *_writingDirectionArray;
+    
+    CGFloat _defaultTabInterval;
+    NSUInteger _domRangeStartIndex;
+    NSInteger _quoteLevel;
+
+    std::unique_ptr&lt;HTMLConverterCaches&gt; _caches;
+
+    struct {
+        unsigned int isSoft:1;
+        unsigned int reachedStart:1;
+        unsigned int reachedEnd:1;
+        unsigned int hasTrailingNewline:1;
+        unsigned int pad:26;
+    } _flags;
+    
+    PlatformColor *_colorForElement(Element&amp;, CSSPropertyID);
+    
+    void _traverseNode(Node&amp;, unsigned depth, bool embedded);
+    void _traverseFooterNode(Element&amp;, unsigned depth);
+    
+    NSDictionary *computedAttributesForElement(Element&amp;);
+    NSDictionary *attributesForElement(Element&amp;);
+    NSDictionary *aggregatedAttributesForAncestors(CharacterData&amp;);
+    NSDictionary* aggregatedAttributesForElementAndItsAncestors(Element&amp;);
+
+    Element* _blockLevelElementForNode(Node*);
+    
+    void _newParagraphForElement(Element&amp;, NSString *tag, BOOL flag, BOOL suppressTrailingSpace);
+    void _newLineForElement(Element&amp;);
+    void _newTabForElement(Element&amp;);
+    BOOL _addAttachmentForElement(Element&amp;, NSURL *url, BOOL needsParagraph, BOOL usePlaceholder);
+    void _addQuoteForElement(Element&amp;, BOOL opening, NSInteger level);
+    void _addValue(NSString *value, Element&amp;);
+    void _fillInBlock(NSTextBlock *block, Element&amp;, PlatformColor *backgroundColor, CGFloat extraMargin, CGFloat extraPadding, BOOL isTable);
+    
+    BOOL _enterElement(Element&amp;, BOOL embedded);
+    BOOL _processElement(Element&amp;, NSInteger depth);
+    void _exitElement(Element&amp;, NSInteger depth, NSUInteger startIndex);
+    
+    void _processHeadElement(Element&amp;);
+    void _processMetaElementWithName(NSString *name, NSString *content);
+    
+    void _addTableForElement(Element* tableElement);
+    void _addTableCellForElement(Element* tableCellElement);
+    void _addMarkersToList(NSTextList *list, NSRange range);
+    void _processText(CharacterData&amp;);
+    void _adjustTrailingNewline();
+};
+
+HTMLConverter::HTMLConverter(Range&amp; range)
+    : m_range(range)
+    , m_dataSource(nullptr)
+{
+    _attrStr = [[NSMutableAttributedString alloc] init];
+    _documentAttrs = [[NSMutableDictionary alloc] init];
+    _baseURL = nil;
+    _textLists = [[NSMutableArray alloc] init];
+    _textBlocks = [[NSMutableArray alloc] init];
+    _textTables = [[NSMutableArray alloc] init];
+    _textTableSpacings = [[NSMutableArray alloc] init];
+    _textTablePaddings = [[NSMutableArray alloc] init];
+    _textTableRows = [[NSMutableArray alloc] init];
+    _textTableRowArrays = [[NSMutableArray alloc] init];
+    _textTableRowBackgroundColors = [[NSMutableArray alloc] init];
+    _fontCache = [[NSMutableDictionary alloc] init];
+    _writingDirectionArray = [[NSMutableArray alloc] init];
+
+    _defaultTabInterval = 36;
+    _domRangeStartIndex = 0;
+    _quoteLevel = 0;
+    
+    _flags.isSoft = false;
+    _flags.reachedStart = false;
+    _flags.reachedEnd = false;
+    
+    _caches = std::make_unique&lt;HTMLConverterCaches&gt;();
+}
+
+HTMLConverter::~HTMLConverter()
+{
+    [_attrStr release];
+    [_documentAttrs release];
+    [_textLists release];
+    [_textBlocks release];
+    [_textTables release];
+    [_textTableSpacings release];
+    [_textTablePaddings release];
+    [_textTableRows release];
+    [_textTableRowArrays release];
+    [_textTableRowBackgroundColors release];
+    [_fontCache release];
+    [_writingDirectionArray release];
+}
+
+NSAttributedString *HTMLConverter::convert()
+{
+    Node* commonAncestorContainer = _caches-&gt;cacheAncestorsOfStartToBeConverted(m_range.get());
+    ASSERT(commonAncestorContainer);
+
+    m_dataSource = commonAncestorContainer-&gt;document().frame()-&gt;loader().documentLoader();
+    if (!m_dataSource)
+        return nil;
+    
+    _domRangeStartIndex = 0;
+    _traverseNode(*commonAncestorContainer, 0, false /* embedded */);
+    if (_domRangeStartIndex &gt; 0 &amp;&amp; _domRangeStartIndex &lt;= [_attrStr length])
+        [_attrStr deleteCharactersInRange:NSMakeRange(0, _domRangeStartIndex)];
+    
+    return [[_attrStr retain] autorelease];
+}
+
+#if !PLATFORM(IOS)
+// Returns the font to be used if the NSFontAttributeName doesn't exist
+static NSFont *WebDefaultFont()
+{
+    static NSFont *defaultFont = nil;
+    if (defaultFont)
+        return defaultFont;
+
+    NSFont *font = [NSFont fontWithName:@&quot;Helvetica&quot; size:12];
+    if (!font)
+        font = [NSFont systemFontOfSize:12];
+
+    defaultFont = [font retain];
+    return defaultFont;
+}
+#endif
+
+static PlatformFont *_fontForNameAndSize(NSString *fontName, CGFloat size, NSMutableDictionary *cache)
+{
+    PlatformFont *font = [cache objectForKey:fontName];
+#if PLATFORM(IOS)
+    if (font)
+        return [font fontWithSize:size];
+
+    font = [PlatformFontClass fontWithName:fontName size:size];
+#else
+    NSFontManager *fontManager = [NSFontManager sharedFontManager];
+    if (font) {
+        font = [fontManager convertFont:font toSize:size];
+        return font;
+    }
+    font = [fontManager fontWithFamily:fontName traits:0 weight:0 size:size];
+#endif
+    if (!font) {
+#if PLATFORM(IOS)
+        NSArray *availableFamilyNames = [PlatformFontClass familyNames];
+#else
+        NSArray *availableFamilyNames = [fontManager availableFontFamilies];
+#endif
+        NSRange dividingRange;
+        NSRange dividingSpaceRange = [fontName rangeOfString:@&quot; &quot; options:NSBackwardsSearch];
+        NSRange dividingDashRange = [fontName rangeOfString:@&quot;-&quot; options:NSBackwardsSearch];
+        dividingRange = (0 &lt; dividingSpaceRange.length &amp;&amp; 0 &lt; dividingDashRange.length) ? (dividingSpaceRange.location &gt; dividingDashRange.location ? dividingSpaceRange : dividingDashRange) : (0 &lt; dividingSpaceRange.length ? dividingSpaceRange : dividingDashRange);
+
+        while (dividingRange.length &gt; 0) {
+            NSString *familyName = [fontName substringToIndex:dividingRange.location];
+            if ([availableFamilyNames containsObject:familyName]) {
+#if PLATFORM(IOS)
+                NSString *faceName = [fontName substringFromIndex:(dividingRange.location + dividingRange.length)];
+                NSArray *familyMemberFaceNames = [PlatformFontClass fontNamesForFamilyName:familyName];
+                for (NSString *familyMemberFaceName in familyMemberFaceNames) {
+                    if ([familyMemberFaceName compare:faceName options:NSCaseInsensitiveSearch] == NSOrderedSame) {
+                        font = [PlatformFontClass fontWithName:familyMemberFaceName size:size];
+                        break;
+                    }
+                }
+                if (!font &amp;&amp; [familyMemberFaceNames count])
+                    font = [getUIFontClass() fontWithName:familyName size:size];
+#else
+                NSArray *familyMemberArray;
+                NSString *faceName = [fontName substringFromIndex:(dividingRange.location + dividingRange.length)];
+                NSArray *familyMemberArrays = [fontManager availableMembersOfFontFamily:familyName];
+                NSEnumerator *familyMemberArraysEnum = [familyMemberArrays objectEnumerator];
+                while ((familyMemberArray = [familyMemberArraysEnum nextObject])) {
+                    NSString *familyMemberFaceName = [familyMemberArray objectAtIndex:1];
+                    if ([familyMemberFaceName compare:faceName options:NSCaseInsensitiveSearch] == NSOrderedSame) {
+                        NSFontTraitMask traits = [[familyMemberArray objectAtIndex:3] integerValue];
+                        NSInteger weight = [[familyMemberArray objectAtIndex:2] integerValue];
+                        font = [fontManager fontWithFamily:familyName traits:traits weight:weight size:size];
+                        break;
+                    }
+                }
+                if (!font) {
+                    if (0 &lt; [familyMemberArrays count]) {
+                        NSArray *familyMemberArray = [familyMemberArrays objectAtIndex:0];
+                        NSFontTraitMask traits = [[familyMemberArray objectAtIndex:3] integerValue];
+                        NSInteger weight = [[familyMemberArray objectAtIndex:2] integerValue];
+                        font = [fontManager fontWithFamily:familyName traits:traits weight:weight size:size];
+                    }
+                }
+#endif
+                break;
+            } else {
+                dividingSpaceRange = [familyName rangeOfString:@&quot; &quot; options:NSBackwardsSearch];
+                dividingDashRange = [familyName rangeOfString:@&quot;-&quot; options:NSBackwardsSearch];
+                dividingRange = (0 &lt; dividingSpaceRange.length &amp;&amp; 0 &lt; dividingDashRange.length) ? (dividingSpaceRange.location &gt; dividingDashRange.location ? dividingSpaceRange : dividingDashRange) : (0 &lt; dividingSpaceRange.length ? dividingSpaceRange : dividingDashRange);
+            }
+        }
+    }
+#if PLATFORM(IOS)
+    if (!font)
+        font = [PlatformFontClass systemFontOfSize:size];
+#else
+    if (!font)
+        font = [NSFont fontWithName:@&quot;Times&quot; size:size];
+    if (!font)
+        font = [NSFont userFontOfSize:size];
+    if (!font)
+        font = [fontManager convertFont:WebDefaultFont() toSize:size];
+    if (!font)
+        font = WebDefaultFont();
+#endif
+    [cache setObject:font forKey:fontName];
+
+    return font;
+}
+
+static NSParagraphStyle *defaultParagraphStyle()
+{
+    static NSMutableParagraphStyle *defaultParagraphStyle = nil;
+    if (!defaultParagraphStyle) {
+        defaultParagraphStyle = [[PlatformNSParagraphStyle defaultParagraphStyle] mutableCopy];
+        [defaultParagraphStyle setDefaultTabInterval:36];
+        [defaultParagraphStyle setTabStops:[NSArray array]];
+    }
+    return defaultParagraphStyle;
+}
+
+PassRefPtr&lt;CSSValue&gt; HTMLConverterCaches::computedStylePropertyForElement(Element&amp; element, CSSPropertyID propertyId)
+{
+    if (propertyId == CSSPropertyInvalid)
+        return nullptr;
+
+    auto result = m_computedStyles.add(&amp;element, nullptr);
+    if (result.isNewEntry)
+        result.iterator-&gt;value = std::make_unique&lt;ComputedStyleExtractor&gt;(&amp;element, true);
+    ComputedStyleExtractor&amp; computedStyle = *result.iterator-&gt;value;
+    return computedStyle.propertyValue(propertyId);
+}
+
+PassRefPtr&lt;CSSValue&gt; HTMLConverterCaches::inlineStylePropertyForElement(Element&amp; element, CSSPropertyID propertyId)
+{
+    if (propertyId == CSSPropertyInvalid || !element.isStyledElement())
+        return nullptr;
+    const StyleProperties* properties = toStyledElement(element).inlineStyle();
+    if (!properties)
+        return nullptr;
+    return properties-&gt;getPropertyCSSValue(propertyId);
+}
+
+static bool stringFromCSSValue(CSSValue&amp; value, String&amp; result)
+{
+    if (value.isPrimitiveValue()) {
+        unsigned short primitiveType = toCSSPrimitiveValue(value).primitiveType();
+        if (primitiveType == CSSPrimitiveValue::CSS_STRING || primitiveType == CSSPrimitiveValue::CSS_URI ||
+            primitiveType == CSSPrimitiveValue::CSS_IDENT || primitiveType == CSSPrimitiveValue::CSS_ATTR) {
+            String stringValue = value.cssText();
+            if (stringValue.length()) {
+                result = stringValue;
+                return true;
+            }
+        }
+    } else if (value.isValueList()) {
+        result = value.cssText();
+        return true;
+    }
+    return false;
+}
+
+String HTMLConverterCaches::propertyValueForNode(Node&amp; node, CSSPropertyID propertyId)
+{
+    if (!node.isElementNode()) {
+        if (Node* parent = node.parentNode())
+            return propertyValueForNode(*parent, propertyId);
+        return String();
+    }
+
+    bool inherit = false;
+    Element&amp; element = toElement(node);
+    if (RefPtr&lt;CSSValue&gt; value = computedStylePropertyForElement(element, propertyId)) {
+        String result;
+        if (stringFromCSSValue(*value, result))
+            return result;
+    }
+
+    if (RefPtr&lt;CSSValue&gt; value = inlineStylePropertyForElement(element, propertyId)) {
+        String result;
+        if (value-&gt;isInheritedValue())
+            inherit = true;
+        else if (stringFromCSSValue(*value, result))
+            return result;
+    }
+
+    switch (propertyId) {
+    case CSSPropertyDisplay:
+        if (element.hasTagName(headTag) || element.hasTagName(scriptTag) || element.hasTagName(appletTag) || element.hasTagName(noframesTag))
+            return &quot;none&quot;;
+        else if (element.hasTagName(addressTag) || element.hasTagName(blockquoteTag) || element.hasTagName(bodyTag) || element.hasTagName(centerTag)
+             || element.hasTagName(ddTag) || element.hasTagName(dirTag) || element.hasTagName(divTag) || element.hasTagName(dlTag)
+             || element.hasTagName(dtTag) || element.hasTagName(fieldsetTag) || element.hasTagName(formTag) || element.hasTagName(frameTag)
+             || element.hasTagName(framesetTag) || element.hasTagName(hrTag) || element.hasTagName(htmlTag) || element.hasTagName(h1Tag)
+             || element.hasTagName(h2Tag) || element.hasTagName(h3Tag) || element.hasTagName(h4Tag) || element.hasTagName(h5Tag)
+             || element.hasTagName(h6Tag) || element.hasTagName(iframeTag) || element.hasTagName(menuTag) || element.hasTagName(noscriptTag)
+             || element.hasTagName(olTag) || element.hasTagName(pTag) || element.hasTagName(preTag) || element.hasTagName(ulTag))
+            return &quot;block&quot;;
+        else if (element.hasTagName(liTag))
+            return &quot;list-item&quot;;
+        else if (element.hasTagName(tableTag))
+            return &quot;table&quot;;
+        else if (element.hasTagName(trTag))
+            return &quot;table-row&quot;;
+        else if (element.hasTagName(thTag) || element.hasTagName(tdTag))
+            return &quot;table-cell&quot;;
+        else if (element.hasTagName(theadTag))
+            return &quot;table-header-group&quot;;
+        else if (element.hasTagName(tbodyTag))
+            return &quot;table-row-group&quot;;
+        else if (element.hasTagName(tfootTag))
+            return &quot;table-footer-group&quot;;
+        else if (element.hasTagName(colTag))
+            return &quot;table-column&quot;;
+        else if (element.hasTagName(colgroupTag))
+            return &quot;table-column-group&quot;;
+        else if (element.hasTagName(captionTag))
+            return &quot;table-caption&quot;;
+        break;
+    case CSSPropertyWhiteSpace:
+        if (element.hasTagName(preTag))
+            return &quot;pre&quot;;
+        inherit = true;
+        break;
+    case CSSPropertyFontStyle:
+        if (element.hasTagName(iTag) || element.hasTagName(citeTag) || element.hasTagName(emTag) || element.hasTagName(varTag) || element.hasTagName(addressTag))
+            return &quot;italic&quot;;
+        inherit = true;
+        break;
+    case CSSPropertyFontWeight:
+        if (element.hasTagName(bTag) || element.hasTagName(strongTag) || element.hasTagName(thTag))
+            return &quot;bolder&quot;;
+        inherit = true;
+        break;
+    case CSSPropertyTextDecoration:
+        if (element.hasTagName(uTag) || element.hasTagName(insTag))
+            return &quot;underline&quot;;
+        else if (element.hasTagName(sTag) || element.hasTagName(strikeTag) || element.hasTagName(delTag))
+            return &quot;line-through&quot;;
+        inherit = true; // FIXME: This is not strictly correct
+        break;
+    case CSSPropertyTextAlign:
+        if (element.hasTagName(centerTag) || element.hasTagName(captionTag) || element.hasTagName(thTag))
+            return &quot;center&quot;;
+        inherit = true;
+        break;
+    case CSSPropertyVerticalAlign:
+        if (element.hasTagName(supTag))
+            return &quot;super&quot;;
+        else if (element.hasTagName(subTag))
+            return &quot;sub&quot;;
+        else if (element.hasTagName(theadTag) || element.hasTagName(tbodyTag) || element.hasTagName(tfootTag))
+            return &quot;middle&quot;;
+        else if (element.hasTagName(trTag) || element.hasTagName(thTag) || element.hasTagName(tdTag))
+            inherit = true;
+        break;
+    case CSSPropertyFontFamily:
+    case CSSPropertyFontVariant:
+    case CSSPropertyTextTransform:
+    case CSSPropertyTextShadow:
+    case CSSPropertyVisibility:
+    case CSSPropertyBorderCollapse:
+    case CSSPropertyEmptyCells:
+    case CSSPropertyWordSpacing:
+    case CSSPropertyListStyleType:
+    case CSSPropertyDirection:
+        inherit = true; // FIXME: Let classes in the css component figure this out.
+        break;
+    default:
+        break;
+    }
+
+    if (inherit) {
+        if (Node* parent = node.parentNode())
+            return propertyValueForNode(*parent, propertyId);
+    }
+    
+    return String();
+}
+
+static inline bool floatValueFromPrimitiveValue(CSSPrimitiveValue&amp; primitiveValue, float&amp; result)
+{
+    // FIXME: Use CSSPrimitiveValue::computeValue.
+    switch (primitiveValue.primitiveType()) {
+    case CSSPrimitiveValue::CSS_PX:
+        result = primitiveValue.getFloatValue(CSSPrimitiveValue::CSS_PX);
+        return true;
+    case CSSPrimitiveValue::CSS_PT:
+        result = 4 * primitiveValue.getFloatValue(CSSPrimitiveValue::CSS_PT) / 3;
+        return true;
+    case CSSPrimitiveValue::CSS_PC:
+        result = 16 * primitiveValue.getFloatValue(CSSPrimitiveValue::CSS_PC);
+        return true;
+    case CSSPrimitiveValue::CSS_CM:
+        result = 96 * primitiveValue.getFloatValue(CSSPrimitiveValue::CSS_PC) / 2.54;
+        return true;
+    case CSSPrimitiveValue::CSS_MM:
+        result = 96 * primitiveValue.getFloatValue(CSSPrimitiveValue::CSS_PC) / 25.4;
+        return true;
+    case CSSPrimitiveValue::CSS_IN:
+        result = 96 * primitiveValue.getFloatValue(CSSPrimitiveValue::CSS_IN);
+        return true;
+    default:
+        return false;
+    }
+}
+
+bool HTMLConverterCaches::floatPropertyValueForNode(Node&amp; node, CSSPropertyID propertyId, float&amp; result)
+{
+    if (!node.isElementNode()) {
+        if (ContainerNode* parent = node.parentNode())
+            return floatPropertyValueForNode(*parent, propertyId, result);
+        return false;
+    }
+
+    Element&amp; element = toElement(node);
+    if (RefPtr&lt;CSSValue&gt; value = computedStylePropertyForElement(element, propertyId)) {
+        if (value-&gt;isPrimitiveValue() &amp;&amp; floatValueFromPrimitiveValue(toCSSPrimitiveValue(*value), result))
+            return true;
+    }
+
+    bool inherit = false;
+    if (RefPtr&lt;CSSValue&gt; value = inlineStylePropertyForElement(element, propertyId)) {
+        if (value-&gt;isPrimitiveValue() &amp;&amp; floatValueFromPrimitiveValue(toCSSPrimitiveValue(*value), result))
+            return true;
+        if (value-&gt;isInheritedValue())
+            inherit = true;
+    }
+
+    switch (propertyId) {
+    case CSSPropertyTextIndent:
+    case CSSPropertyLetterSpacing:
+    case CSSPropertyWordSpacing:
+    case CSSPropertyLineHeight:
+    case CSSPropertyWidows:
+    case CSSPropertyOrphans:
+        inherit = true;
+        break;
+    default:
+        break;
+    }
+
+    if (inherit) {
+        if (ContainerNode* parent = node.parentNode())
+            return floatPropertyValueForNode(*parent, propertyId, result);
+    }
+
+    return false;
+}
+
+#if PLATFORM(IOS)
+static NSString *_NSFirstPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde)
+{
+    NSArray *array = NSSearchPathForDirectoriesInDomains(directory, domainMask, expandTilde);
+    return [array count] &gt;= 1 ? [array objectAtIndex:0] : nil;
+}
+
+static NSString *_NSSystemLibraryPath(void)
+{
+    return _NSFirstPathForDirectoriesInDomains(NSLibraryDirectory, NSSystemDomainMask, YES);
+}
+
+static NSBundle *_webKitBundle()
+{
+    // FIXME: This should probably use the WebCore bundle to avoid the layering violation.
+    NSBundle *bundle = [NSBundle bundleWithIdentifier:@&quot;com.apple.WebKit&quot;];
+    if (!bundle)
+        bundle = [NSBundle bundleWithPath:[_NSSystemLibraryPath() stringByAppendingPathComponent:@&quot;Frameworks/WebKit.framework&quot;]];
+    return bundle;
+}
+
+static inline UIColor *_platformColor(Color color)
+{
+    return [getUIColorClass() _disambiguated_due_to_CIImage_colorWithCGColor:cachedCGColor(color, WebCore::ColorSpaceDeviceRGB)];
+}
+#else
+static inline NSColor *_platformColor(Color color)
+{
+    return nsColor(color);
+}
+#endif
+
+static inline NSShadow *_shadowForShadowStyle(NSString *shadowStyle)
+{
+    NSShadow *shadow = nil;
+    NSUInteger shadowStyleLength = [shadowStyle length];
+    NSRange openParenRange = [shadowStyle rangeOfString:@&quot;(&quot;];
+    NSRange closeParenRange = [shadowStyle rangeOfString:@&quot;)&quot;];
+    NSRange firstRange = NSMakeRange(NSNotFound, 0);
+    NSRange secondRange = NSMakeRange(NSNotFound, 0);
+    NSRange thirdRange = NSMakeRange(NSNotFound, 0);
+    NSRange spaceRange;
+    if (openParenRange.length &gt; 0 &amp;&amp; closeParenRange.length &gt; 0 &amp;&amp; NSMaxRange(openParenRange) &lt; closeParenRange.location) {
+        NSArray *components = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(openParenRange), closeParenRange.location - NSMaxRange(openParenRange))] componentsSeparatedByString:@&quot;,&quot;];
+        if ([components count] &gt;= 3) {
+            CGFloat red = [[components objectAtIndex:0] floatValue] / 255;
+            CGFloat green = [[components objectAtIndex:1] floatValue] / 255;
+            CGFloat blue = [[components objectAtIndex:2] floatValue] / 255;
+            CGFloat alpha = ([components count] &gt;= 4) ? [[components objectAtIndex:3] floatValue] / 255 : 1;
+            NSColor *shadowColor = [PlatformNSColorClass colorWithCalibratedRed:red green:green blue:blue alpha:alpha];
+            NSSize shadowOffset;
+            CGFloat shadowBlurRadius;
+            firstRange = [shadowStyle rangeOfString:@&quot;px&quot;];
+            if (firstRange.length &gt; 0 &amp;&amp; NSMaxRange(firstRange) &lt; shadowStyleLength)
+                secondRange = [shadowStyle rangeOfString:@&quot;px&quot; options:0 range:NSMakeRange(NSMaxRange(firstRange), shadowStyleLength - NSMaxRange(firstRange))];
+            if (secondRange.length &gt; 0 &amp;&amp; NSMaxRange(secondRange) &lt; shadowStyleLength)
+                thirdRange = [shadowStyle rangeOfString:@&quot;px&quot; options:0 range:NSMakeRange(NSMaxRange(secondRange), shadowStyleLength - NSMaxRange(secondRange))];
+            if (firstRange.location &gt; 0 &amp;&amp; firstRange.length &gt; 0 &amp;&amp; secondRange.length &gt; 0 &amp;&amp; thirdRange.length &gt; 0) {
+                spaceRange = [shadowStyle rangeOfString:@&quot; &quot; options:NSBackwardsSearch range:NSMakeRange(0, firstRange.location)];
+                if (spaceRange.length == 0)
+                    spaceRange = NSMakeRange(0, 0);
+                shadowOffset.width = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(spaceRange), firstRange.location - NSMaxRange(spaceRange))] floatValue];
+                spaceRange = [shadowStyle rangeOfString:@&quot; &quot; options:NSBackwardsSearch range:NSMakeRange(0, secondRange.location)];
+                if (!spaceRange.length)
+                    spaceRange = NSMakeRange(0, 0);
+                CGFloat shadowHeight = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(spaceRange), secondRange.location - NSMaxRange(spaceRange))] floatValue];
+                // I don't know why we have this difference between the two platforms.
+#if PLATFORM(IOS)
+                shadowOffset.height = shadowHeight;
+#else
+                shadowOffset.height = -shadowHeight;
+#endif
+                spaceRange = [shadowStyle rangeOfString:@&quot; &quot; options:NSBackwardsSearch range:NSMakeRange(0, thirdRange.location)];
+                if (!spaceRange.length)
+                    spaceRange = NSMakeRange(0, 0);
+                shadowBlurRadius = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(spaceRange), thirdRange.location - NSMaxRange(spaceRange))] floatValue];
+                shadow = [[[PlatformNSShadow alloc] init] autorelease];
+                [shadow setShadowColor:shadowColor];
+                [shadow setShadowOffset:shadowOffset];
+                [shadow setShadowBlurRadius:shadowBlurRadius];
+            }
+        }
+    }
+    return shadow;
+}
+
+bool HTMLConverterCaches::isBlockElement(Element&amp; element)
+{
+    String displayValue = propertyValueForNode(element, CSSPropertyDisplay);
+    if (displayValue == &quot;block&quot; || displayValue == &quot;list-item&quot; || displayValue.startsWith(&quot;table&quot;))
+        return true;
+    String floatValue = propertyValueForNode(element, CSSPropertyFloat);
+    if (floatValue == &quot;left&quot; || floatValue == &quot;right&quot;)
+        return true;
+    return false;
+}
+
+bool HTMLConverterCaches::elementHasOwnBackgroundColor(Element&amp; element)
+{
+    if (!isBlockElement(element))
+        return false;
+    // In the text system, text blocks (table elements) and documents (body elements)
+    // have their own background colors, which should not be inherited.
+    return element.hasTagName(htmlTag) || element.hasTagName(bodyTag) || propertyValueForNode(element, CSSPropertyDisplay).startsWith(&quot;table&quot;);
+}
+
+Element* HTMLConverter::_blockLevelElementForNode(Node* node)
+{
+    Element* element = node-&gt;parentElement();
+    if (element &amp;&amp; !_caches-&gt;isBlockElement(*element))
+        element = _blockLevelElementForNode(element-&gt;parentNode());
+    return element;
+}
+
+static Color normalizedColor(Color color, bool ignoreBlack)
+{
+    const double ColorEpsilon = 1 / (2 * (double)255.0);
+    
+    double red, green, blue, alpha;
+    color.getRGBA(red, green, blue, alpha);
+    if (red &lt; ColorEpsilon &amp;&amp; green &lt; ColorEpsilon &amp;&amp; blue &lt; ColorEpsilon &amp;&amp; (ignoreBlack || alpha &lt; ColorEpsilon))
+        return Color();
+    
+    return color;
+}
+
+Color HTMLConverterCaches::colorPropertyValueForNode(Node&amp; node, CSSPropertyID propertyId)
+{
+    if (!node.isElementNode()) {
+        if (Node* parent = node.parentNode())
+            return colorPropertyValueForNode(*parent, propertyId);
+        return Color();
+    }
+
+    Element&amp; element = toElement(node);
+    if (RefPtr&lt;CSSValue&gt; value = computedStylePropertyForElement(element, propertyId)) {
+        if (value-&gt;isPrimitiveValue() &amp;&amp; toCSSPrimitiveValue(*value).isRGBColor())
+            return normalizedColor(Color(toCSSPrimitiveValue(*value).getRGBA32Value()), propertyId == CSSPropertyColor);
+    }
+
+    bool inherit = false;
+    if (RefPtr&lt;CSSValue&gt; value = inlineStylePropertyForElement(element, propertyId)) {
+        if (value-&gt;isPrimitiveValue() &amp;&amp; toCSSPrimitiveValue(*value).isRGBColor())
+            return normalizedColor(Color(toCSSPrimitiveValue(*value).getRGBA32Value()), propertyId == CSSPropertyColor);
+        if (value-&gt;isInheritedValue())
+            inherit = true;
+    }
+
+    switch (propertyId) {
+    case CSSPropertyColor:
+        inherit = true;
+        break;
+    case CSSPropertyBackgroundColor:
+        if (!elementHasOwnBackgroundColor(element)) {
+            if (Element* parentElement = node.parentElement()) {
+                if (!elementHasOwnBackgroundColor(*parentElement))
+                    inherit = true;
+            }
+        }
+        break;
+    default:
+        break;
+    }
+
+    if (inherit) {
+        if (Node* parent = node.parentNode())
+            return colorPropertyValueForNode(*parent, propertyId);
+    }
+
+    return Color();
+}
+
+PlatformColor *HTMLConverter::_colorForElement(Element&amp; element, CSSPropertyID propertyId)
+{
+    Color result = _caches-&gt;colorPropertyValueForNode(element, propertyId);
+    if (!result.isValid())
+        return nil;
+    PlatformColor *platformResult = _platformColor(result);
+    if ([[PlatformColorClass clearColor] isEqual:platformResult] || ([platformResult alphaComponent] == 0.0))
+        return nil;
+    return platformResult;
+}
+
+#if !PLATFORM(IOS)
+static PlatformFont *_font(Element&amp; element)
+{
+    auto renderer = element.renderer();
+    if (!renderer)
+        return nil;
+    return renderer-&gt;style().font().primaryFont()-&gt;getNSFont();
+}
+#else
+static PlatformFont *_font(Element&amp; element)
+{
+    auto renderer = element.renderer();
+    if (!renderer)
+        return nil;
+    return (PlatformFont *)renderer-&gt;style().font().primaryFont()-&gt;getCTFont();
+}
+#endif
+
+#define UIFloatIsZero(number) (fabs(number - 0) &lt; FLT_EPSILON)
+
+NSDictionary *HTMLConverter::computedAttributesForElement(Element&amp; element)
+{
+    NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
+#if !PLATFORM(IOS)
+    NSFontManager *fontManager = [NSFontManager sharedFontManager];
+#endif
+
+    PlatformFont *font = nil;
+    PlatformFont *actualFont = _font(element);
+    PlatformColor *foregroundColor = _colorForElement(element, CSSPropertyColor);
+    PlatformColor *backgroundColor = _colorForElement(element, CSSPropertyBackgroundColor);
+    PlatformColor *strokeColor = _colorForElement(element, CSSPropertyWebkitTextStrokeColor);
+
+    float fontSize = 0;
+    if (!_caches-&gt;floatPropertyValueForNode(element, CSSPropertyFontSize, fontSize) || fontSize &lt;= 0.0)
+        fontSize = defaultFontSize;
+    if (fontSize &lt; minimumFontSize)
+        fontSize = minimumFontSize;
+    if (fabs(floor(2.0 * fontSize + 0.5) / 2.0 - fontSize) &lt; 0.05)
+        fontSize = floor(2.0 * fontSize + 0.5) / 2;
+    else if (fabs(floor(10.0 * fontSize + 0.5) / 10.0 - fontSize) &lt; 0.005)
+        fontSize = floor(10.0 * fontSize + 0.5) / 10;
+
+    if (fontSize &lt;= 0.0)
+        fontSize = defaultFontSize;
+    
+#if PLATFORM(IOS)
+    if (actualFont)
+        font = [actualFont fontWithSize:fontSize];
+#else
+    if (actualFont)
+        font = [fontManager convertFont:actualFont toSize:fontSize];
+#endif
+    if (!font) {
+        String fontName = _caches-&gt;propertyValueForNode(element, CSSPropertyFontFamily);
+        if (fontName.length())
+            font = _fontForNameAndSize(fontName.upper(), fontSize, _fontCache);
+        if (!font)
+            font = [PlatformFontClass fontWithName:@&quot;Times&quot; size:fontSize];
+
+        String fontStyle = _caches-&gt;propertyValueForNode(element, CSSPropertyFontStyle);
+        if (fontStyle == &quot;italic&quot; || fontStyle == &quot;oblique&quot;) {
+            PlatformFont *originalFont = font;
+#if PLATFORM(IOS)
+            font = [PlatformFontClass fontWithFamilyName:[font familyName] traits:UIFontTraitItalic size:[font pointSize]];
+#else
+            font = [fontManager convertFont:font toHaveTrait:NSItalicFontMask];
+#endif
+            if (!font)
+                font = originalFont;
+        }
+
+        String fontWeight = _caches-&gt;propertyValueForNode(element, CSSPropertyFontStyle);
+        if (fontWeight.startsWith(&quot;bold&quot;) || fontWeight.toInt() &gt;= 700) {
+            // ??? handle weight properly using NSFontManager
+            PlatformFont *originalFont = font;
+#if PLATFORM(IOS)
+            font = [PlatformFontClass fontWithFamilyName:[font familyName] traits:UIFontTraitBold size:[font pointSize]];
+#else
+            font = [fontManager convertFont:font toHaveTrait:NSBoldFontMask];
+#endif
+            if (!font)
+                font = originalFont;
+        }
+#if !PLATFORM(IOS) // IJB: No small caps support on iOS
+        if (_caches-&gt;propertyValueForNode(element, CSSPropertyFontVariant) == &quot;small-caps&quot;) {
+            // ??? synthesize small-caps if [font isEqual:originalFont]
+            NSFont *originalFont = font;
+            font = [fontManager convertFont:font toHaveTrait:NSSmallCapsFontMask];
+            if (!font)
+                font = originalFont;
+        }
+#endif
+    }
+    if (font)
+        [attrs setObject:font forKey:NSFontAttributeName];
+    if (foregroundColor)
+        [attrs setObject:foregroundColor forKey:NSForegroundColorAttributeName];
+    if (backgroundColor &amp;&amp; !_caches-&gt;elementHasOwnBackgroundColor(element))
+        [attrs setObject:backgroundColor forKey:NSBackgroundColorAttributeName];
+
+    float strokeWidth = 0.0;
+    if (_caches-&gt;floatPropertyValueForNode(element, CSSPropertyWebkitTextStrokeWidth, strokeWidth)) {
+        float textStrokeWidth = strokeWidth / ([font pointSize] * 0.01);
+        [attrs setObject:[NSNumber numberWithDouble:textStrokeWidth] forKey:NSStrokeWidthAttributeName];
+    }
+    if (strokeColor)
+        [attrs setObject:strokeColor forKey:NSStrokeColorAttributeName];
+
+    String fontKerning = _caches-&gt;propertyValueForNode(element, CSSPropertyWebkitFontKerning);
+    String letterSpacing = _caches-&gt;propertyValueForNode(element, CSSPropertyLetterSpacing);
+    if (fontKerning.length() || letterSpacing.length()) {
+        if (fontKerning == &quot;none&quot;)
+            [attrs setObject:@0.0 forKey:NSKernAttributeName];
+        else {
+            double kernVal = letterSpacing.length() ? letterSpacing.toDouble() : 0.0;
+            if (UIFloatIsZero(kernVal))
+                [attrs setObject:@0.0 forKey:NSKernAttributeName]; // auto and normal, the other possible values, are both &quot;kerning enabled&quot;
+            else
+                [attrs setObject:[NSNumber numberWithDouble:kernVal] forKey:NSKernAttributeName];
+        }
+    }
+
+    String fontLigatures = _caches-&gt;propertyValueForNode(element, CSSPropertyWebkitFontVariantLigatures);
+    if (fontLigatures.length()) {
+        if (fontLigatures.contains(&quot;normal&quot;))
+            ;   // default: whatever the system decides to do
+        else if (fontLigatures.contains(&quot;common-ligatures&quot;))
+            [attrs setObject:@1 forKey:NSLigatureAttributeName];   // explicitly enabled
+        else if (fontLigatures.contains(&quot;no-common-ligatures&quot;))
+            [attrs setObject:@0 forKey:NSLigatureAttributeName];  // explicitly disabled
+    }
+
+    String textDecoration = _caches-&gt;propertyValueForNode(element, CSSPropertyTextDecoration);
+    if (textDecoration.length()) {
+        if (textDecoration.contains(&quot;underline&quot;))
+            [attrs setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName];
+        if (textDecoration.contains(&quot;line-through&quot;))
+            [attrs setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSStrikethroughStyleAttributeName];
+    }
+
+    String verticalAlign = _caches-&gt;propertyValueForNode(element, CSSPropertyVerticalAlign);
+    if (verticalAlign.length()) {
+        if (verticalAlign == &quot;super&quot;)
+            [attrs setObject:[NSNumber numberWithInteger:1] forKey:NSSuperscriptAttributeName];
+        else if (verticalAlign == &quot;sub&quot;)
+            [attrs setObject:[NSNumber numberWithInteger:-1] forKey:NSSuperscriptAttributeName];
+    }
+
+    float baselineOffset = 0.0;
+    if (_caches-&gt;floatPropertyValueForNode(element, CSSPropertyVerticalAlign, baselineOffset))
+        [attrs setObject:[NSNumber numberWithDouble:baselineOffset] forKey:NSBaselineOffsetAttributeName];
+
+    String textShadow = _caches-&gt;propertyValueForNode(element, CSSPropertyTextShadow);
+    if (textShadow.length() &gt; 4) {
+        NSShadow *shadow = _shadowForShadowStyle(textShadow);
+        if (shadow)
+            [attrs setObject:shadow forKey:NSShadowAttributeName];
+    }
+
+    Element* blockElement = _blockLevelElementForNode(&amp;element);
+    if (&amp;element != blockElement &amp;&amp; [_writingDirectionArray count] &gt; 0)
+        [attrs setObject:[NSArray arrayWithArray:_writingDirectionArray] forKey:NSWritingDirectionAttributeName];
+
+    if (blockElement) {
+        Element&amp; coreBlockElement = *blockElement;
+        NSMutableParagraphStyle *paragraphStyle = [defaultParagraphStyle() mutableCopy];
+        unsigned heading = 0;
+        if (coreBlockElement.hasTagName(h1Tag))
+            heading = 1;
+        else if (coreBlockElement.hasTagName(h2Tag))
+            heading = 2;
+        else if (coreBlockElement.hasTagName(h3Tag))
+            heading = 3;
+        else if (coreBlockElement.hasTagName(h4Tag))
+            heading = 4;
+        else if (coreBlockElement.hasTagName(h5Tag))
+            heading = 5;
+        else if (coreBlockElement.hasTagName(h6Tag))
+            heading = 6;
+        bool isParagraph = coreBlockElement.hasTagName(pTag) || coreBlockElement.hasTagName(liTag) || heading;
+
+        String textAlign = _caches-&gt;propertyValueForNode(coreBlockElement, CSSPropertyTextAlign);
+        if (textAlign.length()) {
+            // WebKit can return -khtml-left, -khtml-right, -khtml-center
+            if (textAlign.endsWith(&quot;left&quot;))
+                [paragraphStyle setAlignment:NSTextAlignmentLeft];
+            else if (textAlign.endsWith(&quot;right&quot;))
+                [paragraphStyle setAlignment:NSTextAlignmentRight];
+            else if (textAlign.endsWith(&quot;center&quot;))
+                [paragraphStyle setAlignment:NSTextAlignmentCenter];
+            else if (textAlign.endsWith(&quot;justify&quot;))
+                [paragraphStyle setAlignment:NSTextAlignmentJustified];
+        }
+
+        String direction = _caches-&gt;propertyValueForNode(coreBlockElement, CSSPropertyDirection);
+        if (direction.length()) {
+            if (direction == &quot;ltr&quot;)
+                [paragraphStyle setBaseWritingDirection:NSWritingDirectionLeftToRight];
+            else if (direction == &quot;rtl&quot;)
+                [paragraphStyle setBaseWritingDirection:NSWritingDirectionRightToLeft];
+        }
+
+        String hyphenation = _caches-&gt;propertyValueForNode(coreBlockElement, CSSPropertyWebkitHyphens);
+        if (hyphenation.length()) {
+            if (hyphenation == &quot;auto&quot;)
+                [paragraphStyle setHyphenationFactor:1.0];
+            else
+                [paragraphStyle setHyphenationFactor:0.0];
+        }
+        if (heading)
+            [paragraphStyle setHeaderLevel:heading];
+        if (isParagraph) {
+            // FIXME: Why are we ignoring margin-top?
+            float marginLeft = 0.0;
+            if (_caches-&gt;floatPropertyValueForNode(coreBlockElement, CSSPropertyMarginLeft, marginLeft) &amp;&amp; marginLeft &gt; 0.0)
+                [paragraphStyle setHeadIndent:marginLeft];
+            float textIndent = 0.0;
+            if (_caches-&gt;floatPropertyValueForNode(coreBlockElement, CSSPropertyTextIndent, textIndent) &amp;&amp; textIndent &gt; 0.0)
+                [paragraphStyle setFirstLineHeadIndent:[paragraphStyle headIndent] + textIndent];
+            float marginRight = 0.0;
+            if (_caches-&gt;floatPropertyValueForNode(coreBlockElement, CSSPropertyMarginRight, marginRight) &amp;&amp; marginRight &gt; 0.0)
+                [paragraphStyle setTailIndent:-marginRight];
+            float marginBottom = 0.0;
+            if (_caches-&gt;floatPropertyValueForNode(coreBlockElement, CSSPropertyMarginRight, marginBottom) &amp;&amp; marginBottom &gt; 0.0)
+                [paragraphStyle setParagraphSpacing:marginBottom];
+        }
+        if ([_textLists count] &gt; 0)
+            [paragraphStyle setTextLists:_textLists];
+        if ([_textBlocks count] &gt; 0)
+            [paragraphStyle setTextBlocks:_textBlocks];
+        [attrs setObject:paragraphStyle forKey:NSParagraphStyleAttributeName];
+        [paragraphStyle release];
+    }
+    return attrs;
+}
+
+
+NSDictionary* HTMLConverter::attributesForElement(Element&amp; element)
+{
+    auto&amp; attributes = m_attributesForElements.add(&amp;element, nullptr).iterator-&gt;value;
+    if (!attributes)
+        attributes = computedAttributesForElement(element);
+    return attributes.get();
+}
+
+NSDictionary* HTMLConverter::aggregatedAttributesForAncestors(CharacterData&amp; node)
+{
+    Node* ancestor = node.parentNode();
+    while (ancestor &amp;&amp; !ancestor-&gt;isElementNode())
+        ancestor = ancestor-&gt;parentNode();
+    if (!ancestor)
+        return nullptr;
+    return aggregatedAttributesForElementAndItsAncestors(*toElement(ancestor));
+}
+
+NSDictionary* HTMLConverter::aggregatedAttributesForElementAndItsAncestors(Element&amp; element)
+{
+    auto&amp; cachedAttributes = m_aggregatedAttributesForElements.add(&amp;element, nullptr).iterator-&gt;value;
+    if (cachedAttributes)
+        return cachedAttributes.get();
+
+    NSDictionary* attributesForCurrentElement = attributesForElement(element);
+    ASSERT(attributesForCurrentElement);
+
+    Node* ancestor = element.parentNode();
+    while (ancestor &amp;&amp; !ancestor-&gt;isElementNode())
+        ancestor = ancestor-&gt;parentNode();
+
+    if (!ancestor) {
+        cachedAttributes = attributesForCurrentElement;
+        return attributesForCurrentElement;
+    }
+
+    RetainPtr&lt;NSMutableDictionary&gt; attributesForAncestors = adoptNS([aggregatedAttributesForElementAndItsAncestors(*toElement(ancestor)) mutableCopy]);
+    [attributesForAncestors addEntriesFromDictionary:attributesForCurrentElement];
+    m_aggregatedAttributesForElements.set(&amp;element, attributesForAncestors);
+
+    return attributesForAncestors.get();
+}
+
+void HTMLConverter::_newParagraphForElement(Element&amp; element, NSString *tag, BOOL flag, BOOL suppressTrailingSpace)
+{
+    NSUInteger textLength = [_attrStr length];
+    unichar lastChar = (textLength &gt; 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n';
+    NSRange rangeToReplace = (suppressTrailingSpace &amp;&amp; _flags.isSoft &amp;&amp; (lastChar == ' ' || lastChar == NSLineSeparatorCharacter)) ? NSMakeRange(textLength - 1, 1) : NSMakeRange(textLength, 0);
+    BOOL needBreak = (flag || lastChar != '\n');
+    if (needBreak) {
+        NSString *string = (([@&quot;BODY&quot; isEqualToString:tag] || [@&quot;HTML&quot; isEqualToString:tag]) ? @&quot;&quot; : @&quot;\n&quot;);
+        [_writingDirectionArray removeAllObjects];
+        [_attrStr replaceCharactersInRange:rangeToReplace withString:string];
+        if (rangeToReplace.location &lt; _domRangeStartIndex)
+            _domRangeStartIndex += [string length] - rangeToReplace.length;
+        rangeToReplace.length = [string length];
+        NSDictionary *attrs = attributesForElement(element);
+        if (rangeToReplace.length &gt; 0)
+            [_attrStr setAttributes:attrs range:rangeToReplace];
+        _flags.isSoft = YES;
+    }
+}
+
+void HTMLConverter::_newLineForElement(Element&amp; element)
+{
+    unichar c = NSLineSeparatorCharacter;
+    RetainPtr&lt;NSString&gt; string = adoptNS([[NSString alloc] initWithCharacters:&amp;c length:1]);
+    NSUInteger textLength = [_attrStr length];
+    NSRange rangeToReplace = NSMakeRange(textLength, 0);
+    [_attrStr replaceCharactersInRange:rangeToReplace withString:string.get()];
+    rangeToReplace.length = [string length];
+    if (rangeToReplace.location &lt; _domRangeStartIndex)
+        _domRangeStartIndex += rangeToReplace.length;
+    NSDictionary *attrs = attributesForElement(element);
+    if (rangeToReplace.length &gt; 0)
+        [_attrStr setAttributes:attrs range:rangeToReplace];
+    _flags.isSoft = YES;
+}
+
+void HTMLConverter::_newTabForElement(Element&amp; element)
+{
+    NSString *string = @&quot;\t&quot;;
+    NSUInteger textLength = [_attrStr length];
+    unichar lastChar = (textLength &gt; 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n';
+    NSRange rangeToReplace = (_flags.isSoft &amp;&amp; lastChar == ' ') ? NSMakeRange(textLength - 1, 1) : NSMakeRange(textLength, 0);
+    [_attrStr replaceCharactersInRange:rangeToReplace withString:string];
+    rangeToReplace.length = [string length];
+    if (rangeToReplace.location &lt; _domRangeStartIndex)
+        _domRangeStartIndex += rangeToReplace.length;
+    NSDictionary *attrs = attributesForElement(element);
+    if (rangeToReplace.length &gt; 0)
+        [_attrStr setAttributes:attrs range:rangeToReplace];
+    _flags.isSoft = YES;
+}
+
+static Class _WebMessageDocumentClass()
+{
+    static Class _WebMessageDocumentClass = Nil;
+    static BOOL lookedUpClass = NO;
+    if (!lookedUpClass) {
+        // If the class is not there, we don't want to try again
+        _WebMessageDocumentClass = objc_lookUpClass(&quot;MFWebMessageDocument&quot;);
+        if (_WebMessageDocumentClass &amp;&amp; ![_WebMessageDocumentClass respondsToSelector:@selector(document:attachment:forURL:)])
+            _WebMessageDocumentClass = Nil;
+        lookedUpClass = YES;
+    }
+    return _WebMessageDocumentClass;
+}
+
+BOOL HTMLConverter::_addAttachmentForElement(Element&amp; element, NSURL *url, BOOL needsParagraph, BOOL usePlaceholder)
+{
+    BOOL retval = NO;
+    BOOL notFound = NO;
+    NSFileWrapper *fileWrapper = nil;
+    Frame* frame = element.document().frame();
+    DocumentLoader *dataSource = frame-&gt;loader().frameHasLoaded() ? frame-&gt;loader().documentLoader() : 0;
+    BOOL ignoreOrientation = YES;
+
+    if ([url isFileURL]) {
+        NSString *path = [[url path] stringByStandardizingPath];
+        if (path)
+            fileWrapper = [[[NSFileWrapper alloc] initWithURL:url options:0 error:NULL] autorelease];
+    }
+    if (!fileWrapper) {
+        RefPtr&lt;ArchiveResource&gt; resource = dataSource-&gt;subresource(url);
+        if (!resource)
+            resource = dataSource-&gt;subresource(url);
+
+        const String&amp; mimeType = resource-&gt;mimeType();
+        if (usePlaceholder &amp;&amp; resource &amp;&amp; mimeType == &quot;text/html&quot;)
+            notFound = YES;
+        if (resource &amp;&amp; !notFound) {
+            fileWrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:resource-&gt;data()-&gt;createNSData().get()] autorelease];
+            [fileWrapper setPreferredFilename:suggestedFilenameWithMIMEType(url, mimeType)];
+        }
+    }
+#if !PLATFORM(IOS)
+    if (!fileWrapper &amp;&amp; !notFound) {
+        fileWrapper = fileWrapperForURL(dataSource, url);
+        if (usePlaceholder &amp;&amp; fileWrapper &amp;&amp; [[[[fileWrapper preferredFilename] pathExtension] lowercaseString] hasPrefix:@&quot;htm&quot;])
+            notFound = YES;
+        if (notFound)
+            fileWrapper = nil;
+    }
+    if (!fileWrapper &amp;&amp; !notFound) {
+        fileWrapper = fileWrapperForURL(m_dataSource, url);
+        if (usePlaceholder &amp;&amp; fileWrapper &amp;&amp; [[[[fileWrapper preferredFilename] pathExtension] lowercaseString] hasPrefix:@&quot;htm&quot;])
+            notFound = YES;
+        if (notFound)
+            fileWrapper = nil;
+    }
+#endif
+    if (!fileWrapper &amp;&amp; !notFound &amp;&amp; url) {
+        // Special handling for Mail attachments, until WebKit provides a standard way to get the data.
+        Class WebMessageDocumentClass = _WebMessageDocumentClass();
+        if (WebMessageDocumentClass) {
+            NSTextAttachment *mimeTextAttachment = nil;
+            [WebMessageDocumentClass document:NULL attachment:&amp;mimeTextAttachment forURL:url];
+            if (mimeTextAttachment &amp;&amp; [mimeTextAttachment respondsToSelector:@selector(fileWrapper)]) {
+                fileWrapper = [mimeTextAttachment performSelector:@selector(fileWrapper)];
+                ignoreOrientation = NO;
+            }
+        }
+    }
+    if (fileWrapper || usePlaceholder) {
+        NSUInteger textLength = [_attrStr length];
+        RetainPtr&lt;NSTextAttachment&gt; attachment = adoptNS([[PlatformNSTextAttachment alloc] initWithFileWrapper:fileWrapper]);
+#if PLATFORM(IOS)
+        float verticalAlign = 0.0;
+        _caches-&gt;floatPropertyValueForNode(element, CSSPropertyVerticalAlign, verticalAlign);
+        attachment.get().bounds = CGRectMake(0, (verticalAlign / 100) * element.clientHeight(), element.clientWidth(), element.clientHeight());
+#endif
+        RetainPtr&lt;NSString&gt; string = adoptNS([[NSString alloc] initWithFormat:(needsParagraph ? @&quot;%C\n&quot; : @&quot;%C&quot;), static_cast&lt;unichar&gt;(NSAttachmentCharacter)]);
+        NSRange rangeToReplace = NSMakeRange(textLength, 0);
+        NSDictionary *attrs;
+        if (fileWrapper) {
+#if !PLATFORM(IOS)
+            if (ignoreOrientation)
+                [attachment setIgnoresOrientation:YES];
+#endif
+        } else {
+#if PLATFORM(IOS)
+            [attachment release];
+            NSURL *missingImageURL = [_webKitBundle() URLForResource:@&quot;missing_image&quot; withExtension:@&quot;tiff&quot;];
+            ASSERT_WITH_MESSAGE(missingImageURL != nil, &quot;Unable to find missing_image.tiff!&quot;);
+            NSFileWrapper *missingImageFileWrapper = [[[NSFileWrapper alloc] initWithURL:missingImageURL options:0 error:NULL] autorelease];
+            attachment = [[PlatformNSTextAttachment alloc] initWithFileWrapper:missingImageFileWrapper];
+#else
+            static NSImage *missingImage = nil;
+            NSTextAttachmentCell *cell;
+            cell = [[NSTextAttachmentCell alloc] initImageCell:missingImage];
+            [attachment setAttachmentCell:cell];
+            [cell release];
+#endif
+        }
+        [_attrStr replaceCharactersInRange:rangeToReplace withString:string.get()];
+        rangeToReplace.length = [string length];
+        if (rangeToReplace.location &lt; _domRangeStartIndex)
+            _domRangeStartIndex += rangeToReplace.length;
+        attrs = attributesForElement(element);
+        if (rangeToReplace.length &gt; 0) {
+            [_attrStr setAttributes:attrs range:rangeToReplace];
+            rangeToReplace.length = 1;
+            [_attrStr addAttribute:NSAttachmentAttributeName value:attachment.get() range:rangeToReplace];
+        }
+        _flags.isSoft = NO;
+        retval = YES;
+    }
+    return retval;
+}
+
+void HTMLConverter::_addQuoteForElement(Element&amp; element, BOOL opening, NSInteger level)
+{
+    unichar c = ((level % 2) == 0) ? (opening ? 0x201c : 0x201d) : (opening ? 0x2018 : 0x2019);
+    RetainPtr&lt;NSString&gt; string = adoptNS([[NSString alloc] initWithCharacters:&amp;c length:1]);
+    NSUInteger textLength = [_attrStr length];
+    NSRange rangeToReplace = NSMakeRange(textLength, 0);
+    [_attrStr replaceCharactersInRange:rangeToReplace withString:string.get()];
+    rangeToReplace.length = [string length];
+    if (rangeToReplace.location &lt; _domRangeStartIndex)
+        _domRangeStartIndex += rangeToReplace.length;
+    RetainPtr&lt;NSDictionary&gt; attrs = attributesForElement(element);
+    if (rangeToReplace.length &gt; 0)
+        [_attrStr setAttributes:attrs.get() range:rangeToReplace];
+    _flags.isSoft = NO;
+}
+
+void HTMLConverter::_addValue(NSString *value, Element&amp; element)
+{
+    NSUInteger textLength = [_attrStr length];
+    NSUInteger valueLength = [value length];
+    NSRange rangeToReplace = NSMakeRange(textLength, 0);
+    if (valueLength) {
+        [_attrStr replaceCharactersInRange:rangeToReplace withString:value];
+        rangeToReplace.length = valueLength;
+        if (rangeToReplace.location &lt; _domRangeStartIndex)
+            _domRangeStartIndex += rangeToReplace.length;
+        RetainPtr&lt;NSDictionary&gt; attrs = attributesForElement(element);
+        if (rangeToReplace.length &gt; 0)
+            [_attrStr setAttributes:attrs.get() range:rangeToReplace];
+        _flags.isSoft = NO;
+    }
+}
+
+void HTMLConverter::_fillInBlock(NSTextBlock *block, Element&amp; element, PlatformColor *backgroundColor, CGFloat extraMargin, CGFloat extraPadding, BOOL isTable)
+{
+    float result = 0;
+    
+    NSString *width = element.getAttribute(widthAttr);
+    if ((width &amp;&amp; [width length]) || !isTable) {
+        if (_caches-&gt;floatPropertyValueForNode(element, CSSPropertyWidth, result))
+            [block setValue:result type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockWidth];
+    }
+    
+    if (_caches-&gt;floatPropertyValueForNode(element, CSSPropertyMinWidth, result))
+        [block setValue:result type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMinimumWidth];
+    if (_caches-&gt;floatPropertyValueForNode(element, CSSPropertyMaxWidth, result))
+        [block setValue:result type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMaximumWidth];
+    if (_caches-&gt;floatPropertyValueForNode(element, CSSPropertyMinHeight, result))
+        [block setValue:result type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMinimumHeight];
+    if (_caches-&gt;floatPropertyValueForNode(element, CSSPropertyMaxHeight, result))
+        [block setValue:result type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMaximumHeight];
+
+    if (_caches-&gt;floatPropertyValueForNode(element, CSSPropertyPaddingLeft, result))
+        [block setWidth:result + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinXEdge];
+    else
+        [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinXEdge];
+    
+    if (_caches-&gt;floatPropertyValueForNode(element, CSSPropertyPaddingTop, result))
+        [block setWidth:result + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinYEdge];
+    else
+        [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinYEdge];
+    
+    if (_caches-&gt;floatPropertyValueForNode(element, CSSPropertyPaddingRight, result))
+        [block setWidth:result + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxXEdge];
+    else
+        [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxXEdge];
+    
+    if (_caches-&gt;floatPropertyValueForNode(element, CSSPropertyPaddingBottom, result))
+        [block setWidth:result + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxYEdge];
+    else
+        [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxYEdge];
+    
+    if (_caches-&gt;floatPropertyValueForNode(element, CSSPropertyBorderLeftWidth, result))
+        [block setWidth:result type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMinXEdge];
+    if (_caches-&gt;floatPropertyValueForNode(element, CSSPropertyBorderTopWidth, result))
+        [block setWidth:result type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMinYEdge];
+    if (_caches-&gt;floatPropertyValueForNode(element, CSSPropertyBorderRightWidth, result))
+        [block setWidth:result type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMaxXEdge];
+    if (_caches-&gt;floatPropertyValueForNode(element, CSSPropertyBorderBottomWidth, result))
+        [block setWidth:result type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMaxYEdge];
+
+    if (_caches-&gt;floatPropertyValueForNode(element, CSSPropertyMarginLeft, result))
+        [block setWidth:result + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinXEdge];
+    else
+        [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinXEdge];
+    if (_caches-&gt;floatPropertyValueForNode(element, CSSPropertyMarginTop, result))
+        [block setWidth:result + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinYEdge];
+    else
+        [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinYEdge];
+    if (_caches-&gt;floatPropertyValueForNode(element, CSSPropertyMarginRight, result))
+        [block setWidth:result + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxXEdge];
+    else
+        [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxXEdge];
+    if (_caches-&gt;floatPropertyValueForNode(element, CSSPropertyMarginBottom, result))
+        [block setWidth:result + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxYEdge];
+    else
+        [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxYEdge];
+    
+    PlatformColor *color = nil;
+    if ((color = _colorForElement(element, CSSPropertyBackgroundColor)))
+        [block setBackgroundColor:color];
+    if (!color &amp;&amp; backgroundColor)
+        [block setBackgroundColor:backgroundColor];
+    
+    if ((color = _colorForElement(element, CSSPropertyBorderLeftColor)))
+        [block setBorderColor:color forEdge:NSMinXEdge];
+    
+    if ((color = _colorForElement(element, CSSPropertyBorderTopColor)))
+        [block setBorderColor:color forEdge:NSMinYEdge];
+    if ((color = _colorForElement(element, CSSPropertyBorderRightColor)))
+        [block setBorderColor:color forEdge:NSMaxXEdge];
+    if ((color = _colorForElement(element, CSSPropertyBorderBottomColor)))
+        [block setBorderColor:color forEdge:NSMaxYEdge];
+}
+
+static inline BOOL read2DigitNumber(const char **pp, int8_t *outval)
+{
+    BOOL result = NO;
+    char c1 = *(*pp)++, c2;
+    if (isASCIIDigit(c1)) {
+        c2 = *(*pp)++;
+        if (isASCIIDigit(c2)) {
+            *outval = 10 * (c1 - '0') + (c2 - '0');
+            result = YES;
+        }
+    }
+    return result;
+}
+
+static inline NSDate *_dateForString(NSString *string)
+{
+    const char *p = [string UTF8String];
+    RetainPtr&lt;NSDateComponents&gt; dateComponents = adoptNS([[NSDateComponents alloc] init]);
+
+    // Set the time zone to GMT
+    [dateComponents setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
+
+    NSInteger year = 0;
+    while (*p &amp;&amp; isASCIIDigit(*p))
+        year = 10 * year + *p++ - '0';
+    if (*p++ != '-')
+        return nil;
+    [dateComponents setYear:year];
+
+    int8_t component;
+    if (!read2DigitNumber(&amp;p, &amp;component) || *p++ != '-')
+        return nil;
+    [dateComponents setMonth:component];
+
+    if (!read2DigitNumber(&amp;p, &amp;component) || *p++ != 'T')
+        return nil;
+    [dateComponents setDay:component];
+
+    if (!read2DigitNumber(&amp;p, &amp;component) || *p++ != ':')
+        return nil;
+    [dateComponents setHour:component];
+
+    if (!read2DigitNumber(&amp;p, &amp;component) || *p++ != ':')
+        return nil;
+    [dateComponents setMinute:component];
+
+    if (!read2DigitNumber(&amp;p, &amp;component) || *p++ != 'Z')
+        return nil;
+    [dateComponents setSecond:component];
+    
+#if (PLATFORM(IOS) &amp;&amp; __IPHONE_OS_VERSION_MIN_REQUIRED &gt;= 80000) || (PLATFORM(MAC) &amp;&amp; __MAC_OS_X_VERSION_MIN_REQUIRED &gt;= 1090)
+    NSString *calendarIdentifier = NSCalendarIdentifierGregorian;
+#else
+    NSString *calendarIdentifier = NSGregorianCalendar;
+#endif
+
+    return [[[[NSCalendar alloc] initWithCalendarIdentifier:calendarIdentifier] autorelease] dateFromComponents:dateComponents.get()];
+}
+
+static NSInteger _colCompare(id block1, id block2, void *)
+{
+    NSInteger col1 = [(NSTextTableBlock *)block1 startingColumn];
+    NSInteger col2 = [(NSTextTableBlock *)block2 startingColumn];
+    return ((col1 &lt; col2) ? NSOrderedAscending : ((col1 == col2) ? NSOrderedSame : NSOrderedDescending));
+}
+
+void HTMLConverter::_processMetaElementWithName(NSString *name, NSString *content)
+{
+    NSString *key = nil;
+    if (NSOrderedSame == [@&quot;CocoaVersion&quot; compare:name options:NSCaseInsensitiveSearch]) {
+        CGFloat versionNumber = [content doubleValue];
+        if (versionNumber &gt; 0.0) {
+            // ??? this should be keyed off of version number in future
+            [_documentAttrs removeObjectForKey:NSConvertedDocumentAttribute];
+            [_documentAttrs setObject:[NSNumber numberWithDouble:versionNumber] forKey:NSCocoaVersionDocumentAttribute];
+        }
+#if PLATFORM(IOS)
+    } else if (NSOrderedSame == [@&quot;Generator&quot; compare:name options:NSCaseInsensitiveSearch]) {
+        key = NSGeneratorDocumentAttribute;
+#endif
+    } else if (NSOrderedSame == [@&quot;Keywords&quot; compare:name options:NSCaseInsensitiveSearch]) {
+        if (content &amp;&amp; [content length] &gt; 0) {
+            NSArray *array;
+            // ??? need better handling here and throughout
+            if ([content rangeOfString:@&quot;, &quot;].length == 0 &amp;&amp; [content rangeOfString:@&quot;,&quot;].length &gt; 0)
+                array = [content componentsSeparatedByString:@&quot;,&quot;];
+            else if ([content rangeOfString:@&quot;, &quot;].length == 0 &amp;&amp; [content rangeOfString:@&quot; &quot;].length &gt; 0)
+                array = [content componentsSeparatedByString:@&quot; &quot;];
+            else
+                array = [content componentsSeparatedByString:@&quot;, &quot;];
+            [_documentAttrs setObject:array forKey:NSKeywordsDocumentAttribute];
+        }
+    } else if (NSOrderedSame == [@&quot;Author&quot; compare:name options:NSCaseInsensitiveSearch])
+        key = NSAuthorDocumentAttribute;
+    else if (NSOrderedSame == [@&quot;LastAuthor&quot; compare:name options:NSCaseInsensitiveSearch])
+        key = NSEditorDocumentAttribute;
+    else if (NSOrderedSame == [@&quot;Company&quot; compare:name options:NSCaseInsensitiveSearch])
+        key = NSCompanyDocumentAttribute;
+    else if (NSOrderedSame == [@&quot;Copyright&quot; compare:name options:NSCaseInsensitiveSearch])
+        key = NSCopyrightDocumentAttribute;
+    else if (NSOrderedSame == [@&quot;Subject&quot; compare:name options:NSCaseInsensitiveSearch])
+        key = NSSubjectDocumentAttribute;
+    else if (NSOrderedSame == [@&quot;Description&quot; compare:name options:NSCaseInsensitiveSearch] || NSOrderedSame == [@&quot;Comment&quot; compare:name options:NSCaseInsensitiveSearch])
+        key = NSCommentDocumentAttribute;
+    else if (NSOrderedSame == [@&quot;CreationTime&quot; compare:name options:NSCaseInsensitiveSearch]) {
+        if (content &amp;&amp; [content length] &gt; 0) {
+            NSDate *date = _dateForString(content);
+            if (date)
+                [_documentAttrs setObject:date forKey:NSCreationTimeDocumentAttribute];
+        }
+    } else if (NSOrderedSame == [@&quot;ModificationTime&quot; compare:name options:NSCaseInsensitiveSearch]) {
+        if (content &amp;&amp; [content length] &gt; 0) {
+            NSDate *date = _dateForString(content);
+            if (date)
+                [_documentAttrs setObject:date forKey:NSModificationTimeDocumentAttribute];
+        }
+    }
+#if PLATFORM(IOS)
+    else if (NSOrderedSame == [@&quot;DisplayName&quot; compare:name options:NSCaseInsensitiveSearch] || NSOrderedSame == [@&quot;IndexTitle&quot; compare:name options:NSCaseInsensitiveSearch])
+        key = NSDisplayNameDocumentAttribute;
+    else if (NSOrderedSame == [@&quot;robots&quot; compare:name options:NSCaseInsensitiveSearch]) {
+        if ([content rangeOfString:@&quot;noindex&quot; options:NSCaseInsensitiveSearch].length &gt; 0)
+            [_documentAttrs setObject:[NSNumber numberWithInteger:1] forKey:NSNoIndexDocumentAttribute];
+    }
+#endif
+    if (key &amp;&amp; content &amp;&amp; [content length] &gt; 0)
+        [_documentAttrs setObject:content forKey:key];
+}
+
+void HTMLConverter::_processHeadElement(Element&amp; element)
+{
+    // FIXME: Should gather data from other sources e.g. Word, but for that we would need to be able to get comments from DOM
+    
+    for (HTMLMetaElement* child = Traversal&lt;HTMLMetaElement&gt;::firstChild(&amp;element); child; child = Traversal&lt;HTMLMetaElement&gt;::nextSibling(child)) {
+        NSString *name = child-&gt;name();
+        NSString *content = child-&gt;content();
+        if (name &amp;&amp; content)
+            _processMetaElementWithName(name, content);
+    }
+}
+
+BOOL HTMLConverter::_enterElement(Element&amp; element, BOOL embedded)
+{
+    String displayValue = _caches-&gt;propertyValueForNode(element, CSSPropertyDisplay);
+
+    if (element.hasTagName(headTag) &amp;&amp; !embedded)
+        _processHeadElement(element);
+    else if (!displayValue.length() || !(displayValue == &quot;none&quot; || displayValue == &quot;table-column&quot; || displayValue == &quot;table-column-group&quot;)) {
+        if (_caches-&gt;isBlockElement(element) &amp;&amp; !element.hasTagName(brTag) &amp;&amp; !(displayValue == &quot;table-cell&quot; &amp;&amp; [_textTables count] == 0)
+            &amp;&amp; !([_textLists count] &gt; 0 &amp;&amp; displayValue == &quot;block&quot; &amp;&amp; !element.hasTagName(liTag) &amp;&amp; !element.hasTagName(ulTag) &amp;&amp; !element.hasTagName(olTag)))
+            _newParagraphForElement(element, element.tagName(), NO, YES);
+        return YES;
+    }
+    return NO;
+}
+
+void HTMLConverter::_addTableForElement(Element *tableElement)
+{
+    RetainPtr&lt;NSTextTable&gt; table = adoptNS([[PlatformNSTextTable alloc] init]);
+    CGFloat cellSpacingVal = 1;
+    CGFloat cellPaddingVal = 1;
+    [table setNumberOfColumns:1];
+    [table setLayoutAlgorithm:NSTextTableAutomaticLayoutAlgorithm];
+    [table setCollapsesBorders:NO];
+    [table setHidesEmptyCells:NO];
+    
+    if (tableElement) {
+        ASSERT(tableElement);
+        Element&amp; coreTableElement = *tableElement;
+        
+        NSString *cellSpacing = coreTableElement.getAttribute(cellspacingAttr);
+        if (cellSpacing &amp;&amp; [cellSpacing length] &gt; 0 &amp;&amp; ![cellSpacing hasSuffix:@&quot;%&quot;])
+            cellSpacingVal = [cellSpacing floatValue];
+        NSString *cellPadding = coreTableElement.getAttribute(cellpaddingAttr);
+        if (cellPadding &amp;&amp; [cellPadding length] &gt; 0 &amp;&amp; ![cellPadding hasSuffix:@&quot;%&quot;])
+            cellPaddingVal = [cellPadding floatValue];
+        
+        _fillInBlock(table.get(), coreTableElement, nil, 0, 0, YES);
+
+        if (_caches-&gt;propertyValueForNode(coreTableElement, CSSPropertyBorderCollapse) == &quot;collapse&quot;) {
+            [table setCollapsesBorders:YES];
+            cellSpacingVal = 0;
+        }
+        if (_caches-&gt;propertyValueForNode(coreTableElement, CSSPropertyEmptyCells) == &quot;hide&quot;)
+            [table setHidesEmptyCells:YES];
+        if (_caches-&gt;propertyValueForNode(coreTableElement, CSSPropertyTableLayout) == &quot;fixed&quot;)
+            [table setLayoutAlgorithm:NSTextTableFixedLayoutAlgorithm];
+    }
+    
+    [_textTables addObject:table.get()];
+    [_textTableSpacings addObject:[NSNumber numberWithDouble:cellSpacingVal]];
+    [_textTablePaddings addObject:[NSNumber numberWithDouble:cellPaddingVal]];
+    [_textTableRows addObject:[NSNumber numberWithInteger:0]];
+    [_textTableRowArrays addObject:[NSMutableArray array]];
+}
+
+void HTMLConverter::_addTableCellForElement(Element* element)
+{
+    NSTextTable *table = [_textTables lastObject];
+    NSInteger rowNumber = [[_textTableRows lastObject] integerValue];
+    NSInteger columnNumber = 0;
+    NSInteger rowSpan = 1;
+    NSInteger colSpan = 1;
+    NSMutableArray *rowArray = [_textTableRowArrays lastObject];
+    NSUInteger count = [rowArray count];
+    PlatformColor *color = ([_textTableRowBackgroundColors count] &gt; 0) ? [_textTableRowBackgroundColors lastObject] : nil;
+    NSTextTableBlock *previousBlock;
+    CGFloat cellSpacingVal = [[_textTableSpacings lastObject] floatValue];
+    if ([color isEqual:[PlatformColorClass clearColor]]) color = nil;
+    for (NSUInteger i = 0; i &lt; count; i++) {
+        previousBlock = [rowArray objectAtIndex:i];
+        if (columnNumber &gt;= [previousBlock startingColumn] &amp;&amp; columnNumber &lt; [previousBlock startingColumn] + [previousBlock columnSpan])
+            columnNumber = [previousBlock startingColumn] + [previousBlock columnSpan];
+    }
+    
+    RetainPtr&lt;NSTextTableBlock&gt; block;
+    
+    if (element) {
+        if (isHTMLTableCellElement(*element)) {
+            HTMLTableCellElement&amp; tableCellElement = toHTMLTableCellElement(*element);
+            
+            rowSpan = tableCellElement.rowSpan();
+            if (rowSpan &lt; 1)
+                rowSpan = 1;
+            colSpan = tableCellElement.colSpan();
+            if (colSpan &lt; 1)
+                colSpan = 1;
+        }
+        
+        block = adoptNS([[PlatformNSTextTableBlock alloc] initWithTable:table startingRow:rowNumber rowSpan:rowSpan startingColumn:columnNumber columnSpan:colSpan]);
+        
+        String verticalAlign = _caches-&gt;propertyValueForNode(*element, CSSPropertyVerticalAlign);
+        
+        _fillInBlock(block.get(), *element, color, cellSpacingVal / 2, 0, NO);
+        if (verticalAlign == &quot;middle&quot;)
+            [block setVerticalAlignment:NSTextBlockMiddleAlignment];
+        else if (verticalAlign == &quot;bottom&quot;)
+            [block setVerticalAlignment:NSTextBlockBottomAlignment];
+        else if (verticalAlign == &quot;baseline&quot;)
+            [block setVerticalAlignment:NSTextBlockBaselineAlignment];
+        else if (verticalAlign == &quot;top&quot;)
+            [block setVerticalAlignment:NSTextBlockTopAlignment];
+    } else {
+        block = adoptNS([[PlatformNSTextTableBlock alloc] initWithTable:table startingRow:rowNumber rowSpan:rowSpan startingColumn:columnNumber columnSpan:colSpan]);
+    }
+    
+    [_textBlocks addObject:block.get()];
+    [rowArray addObject:block.get()];
+    [rowArray sortUsingFunction:_colCompare context:NULL];
+}
+
+BOOL HTMLConverter::_processElement(Element&amp; element, NSInteger depth)
+{
+    BOOL retval = YES;
+    BOOL isBlockLevel = _caches-&gt;isBlockElement(element);
+    String displayValue = _caches-&gt;propertyValueForNode(element, CSSPropertyDisplay);
+    if (isBlockLevel)
+        [_writingDirectionArray removeAllObjects];
+    else {
+        String bidi = _caches-&gt;propertyValueForNode(element, CSSPropertyUnicodeBidi);
+        if (bidi == &quot;embed&quot;) {
+            NSUInteger val = NSTextWritingDirectionEmbedding;
+            if (_caches-&gt;propertyValueForNode(element, CSSPropertyDirection) == &quot;rtl&quot;)
+                val |= NSWritingDirectionRightToLeft;
+            [_writingDirectionArray addObject:[NSNumber numberWithUnsignedInteger:val]];
+        } else if (bidi == &quot;bidi-override&quot;) {
+            NSUInteger val = NSTextWritingDirectionOverride;
+            if (_caches-&gt;propertyValueForNode(element, CSSPropertyDirection) == &quot;rtl&quot;)
+                val |= NSWritingDirectionRightToLeft;
+            [_writingDirectionArray addObject:[NSNumber numberWithUnsignedInteger:val]];
+        }
+    }
+    if (displayValue == &quot;table&quot; || ([_textTables count] == 0 &amp;&amp; displayValue == &quot;table-row-group&quot;)) {
+        Element* tableElement = &amp;element;
+        if (displayValue == &quot;table-row-group&quot;) {
+            // If we are starting in medias res, the first thing we see may be the tbody, so go up to the table
+            tableElement = _blockLevelElementForNode(element.parentNode());
+            if (!tableElement || _caches-&gt;propertyValueForNode(*tableElement, CSSPropertyDisplay) != &quot;table&quot;)
+                tableElement = &amp;element;
+        }
+        while ([_textTables count] &gt; [_textBlocks count])
+            _addTableCellForElement(nil);
+        _addTableForElement(tableElement);
+    } else if (displayValue == &quot;table-footer-group&quot; &amp;&amp; [_textTables count] &gt; 0) {
+        m_textTableFooters.add([_textTables lastObject], &amp;element);
+        retval = NO;
+    } else if (displayValue == &quot;table-row&quot; &amp;&amp; [_textTables count] &gt; 0) {
+        PlatformColor *color = _colorForElement(element, CSSPropertyBackgroundColor);
+        if (!color)
+            color = [PlatformColorClass clearColor];
+        [_textTableRowBackgroundColors addObject:color];
+    } else if (displayValue == &quot;table-cell&quot;) {
+        while ([_textTables count] &lt; [_textBlocks count] + 1)
+            _addTableForElement(nil);
+        _addTableCellForElement(&amp;element);
+    } else if (element.hasTagName(imgTag)) {
+        NSString *urlString = element.getAttribute(srcAttr);
+        if (urlString &amp;&amp; [urlString length] &gt; 0) {
+            NSURL *url = element.document().completeURL(stripLeadingAndTrailingHTMLSpaces(urlString));
+            if (!url)
+                url = [NSURL _web_URLWithString:[urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] relativeToURL:_baseURL];
+#if PLATFORM(IOS)
+            BOOL usePlaceholderImage = NO;
+#else
+            BOOL usePlaceholderImage = YES;
+#endif
+            if (url)
+                _addAttachmentForElement(element, url, isBlockLevel, usePlaceholderImage);
+        }
+        retval = NO;
+    } else if (element.hasTagName(objectTag)) {
+        NSString *baseString = element.getAttribute(codebaseAttr);
+        NSString *urlString = element.getAttribute(dataAttr);
+        NSString *declareString = element.getAttribute(declareAttr);
+        if (urlString &amp;&amp; [urlString length] &gt; 0 &amp;&amp; ![@&quot;true&quot; isEqualToString:declareString]) {
+            NSURL *baseURL = nil;
+            NSURL *url = nil;
+            if (baseString &amp;&amp; [baseString length] &gt; 0) {
+                baseURL = element.document().completeURL(stripLeadingAndTrailingHTMLSpaces(baseString));
+                if (!baseURL)
+                    baseURL = [NSURL _web_URLWithString:[baseString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] relativeToURL:_baseURL];
+            }
+            if (baseURL)
+                url = [NSURL _web_URLWithString:[urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] relativeToURL:baseURL];
+            if (!url)
+                url = element.document().completeURL(stripLeadingAndTrailingHTMLSpaces(urlString));
+            if (!url)
+                url = [NSURL _web_URLWithString:[urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] relativeToURL:_baseURL];
+            if (url)
+                retval = !_addAttachmentForElement(element, url, isBlockLevel, NO);
+        }
+    } else if (element.hasTagName(frameTag) || element.hasTagName(iframeTag)) {
+        if (Document* contentDocument = toHTMLFrameElementBase(element).contentDocument()) {
+            _traverseNode(*contentDocument, depth + 1, true /* embedded */);
+            retval = NO;
+        }
+    } else if (element.hasTagName(brTag)) {
+        Element* blockElement = _blockLevelElementForNode(element.parentNode());
+        NSString *breakClass = element.getAttribute(classAttr);
+        NSString *blockTag = blockElement ? (NSString *)blockElement-&gt;tagName() : nil;
+        BOOL isExtraBreak = [@&quot;Apple-interchange-newline&quot; isEqualToString:breakClass];
+        BOOL blockElementIsParagraph = ([@&quot;P&quot; isEqualToString:blockTag] || [@&quot;LI&quot; isEqualToString:blockTag] || ([blockTag hasPrefix:@&quot;H&quot;] &amp;&amp; 2 == [blockTag length]));
+        if (isExtraBreak)
+            _flags.hasTrailingNewline = YES;
+        else {
+            if (blockElement &amp;&amp; blockElementIsParagraph)
+                _newLineForElement(element);
+            else
+                _newParagraphForElement(element, element.tagName(), YES, NO);
+        }
+    } else if (element.hasTagName(ulTag)) {
+        RetainPtr&lt;NSTextList&gt; list;
+        String listStyleType = _caches-&gt;propertyValueForNode(element, CSSPropertyListStyleType);
+        if (!listStyleType.length())
+            listStyleType = @&quot;disc&quot;;
+        list = adoptNS([[PlatformNSTextList alloc] initWithMarkerFormat:String(&quot;{&quot; + listStyleType + &quot;}&quot;) options:0]);
+        [_textLists addObject:list.get()];
+    } else if (element.hasTagName(olTag)) {
+        RetainPtr&lt;NSTextList&gt; list;
+        String listStyleType = _caches-&gt;propertyValueForNode(element, CSSPropertyListStyleType);
+        if (!listStyleType.length())
+            listStyleType = &quot;decimal&quot;;
+        list = adoptNS([[PlatformNSTextList alloc] initWithMarkerFormat:String(&quot;{&quot; + listStyleType + &quot;}&quot;) options:0]);
+        if (isHTMLOListElement(element)) {
+            NSInteger startingItemNumber = toHTMLOListElement(element).start();;
+            [list setStartingItemNumber:startingItemNumber];
+        }
+        [_textLists addObject:list.get()];
+    } else if (element.hasTagName(qTag)) {
+        _addQuoteForElement(element, YES, _quoteLevel++);
+    } else if (element.hasTagName(inputTag)) {
+        if (isHTMLInputElement(element)) {
+            HTMLInputElement&amp; inputElement = toHTMLInputElement(element);
+            if (inputElement.type() == &quot;text&quot;) {
+                NSString *value = inputElement.value();
+                if (value &amp;&amp; [value length] &gt; 0)
+                    _addValue(value, element);
+            }
+        }
+    } else if (element.hasTagName(textareaTag)) {
+        if (isHTMLTextAreaElement(element)) {
+            HTMLTextAreaElement&amp; textAreaElement = toHTMLTextAreaElement(element);
+            NSString *value = textAreaElement.value();
+            if (value &amp;&amp; [value length] &gt; 0)
+                _addValue(value, element);
+        }
+        retval = NO;
+    }
+    return retval;
+}
+
+void HTMLConverter::_addMarkersToList(NSTextList *list, NSRange range)
+{
+    NSInteger itemNum = [list startingItemNumber];
+    NSString *string = [_attrStr string];
+    NSString *stringToInsert;
+    NSDictionary *attrsToInsert = nil;
+    PlatformFont *font;
+    NSParagraphStyle *paragraphStyle;
+    NSMutableParagraphStyle *newStyle;
+    NSTextTab *tab = nil;
+    NSTextTab *tabToRemove;
+    NSRange paragraphRange;
+    NSRange styleRange;
+    NSUInteger textLength = [_attrStr length];
+    NSUInteger listIndex;
+    NSUInteger insertLength;
+    NSUInteger i;
+    NSUInteger count;
+    NSArray *textLists;
+    CGFloat markerLocation;
+    CGFloat listLocation;
+    CGFloat pointSize;
+    
+    if (range.length == 0 || range.location &gt;= textLength)
+        return;
+    if (NSMaxRange(range) &gt; textLength)
+        range.length = textLength - range.location;
+    paragraphStyle = [_attrStr attribute:NSParagraphStyleAttributeName atIndex:range.location effectiveRange:NULL];
+    if (paragraphStyle) {
+        textLists = [paragraphStyle textLists];
+        listIndex = [textLists indexOfObject:list];
+        if (textLists &amp;&amp; listIndex != NSNotFound) {
+            for (NSUInteger idx = range.location; idx &lt; NSMaxRange(range);) {
+                paragraphRange = [string paragraphRangeForRange:NSMakeRange(idx, 0)];
+                paragraphStyle = [_attrStr attribute:NSParagraphStyleAttributeName atIndex:idx effectiveRange:&amp;styleRange];
+                font = [_attrStr attribute:NSFontAttributeName atIndex:idx effectiveRange:NULL];
+                pointSize = font ? [font pointSize] : 12;
+                if ([[paragraphStyle textLists] count] == listIndex + 1) {
+                    stringToInsert = [NSString stringWithFormat:@&quot;\t%@\t&quot;, [list markerForItemNumber:itemNum++]];
+                    insertLength = [stringToInsert length];
+                    attrsToInsert = [PlatformNSTextList _standardMarkerAttributesForAttributes:[_attrStr attributesAtIndex:paragraphRange.location effectiveRange:NULL]];
+
+                    [_attrStr replaceCharactersInRange:NSMakeRange(paragraphRange.location, 0) withString:stringToInsert];
+                    [_attrStr setAttributes:attrsToInsert range:NSMakeRange(paragraphRange.location, insertLength)];
+                    range.length += insertLength;
+                    paragraphRange.length += insertLength;
+                    if (paragraphRange.location &lt; _domRangeStartIndex)
+                        _domRangeStartIndex += insertLength;
+                    
+                    newStyle = [paragraphStyle mutableCopy];
+                    listLocation = (listIndex + 1) * 36;
+                    markerLocation = listLocation - 25;
+                    [newStyle setFirstLineHeadIndent:0];
+                    [newStyle setHeadIndent:listLocation];
+                    while ((count = [[newStyle tabStops] count]) &gt; 0) {
+                        for (i = 0, tabToRemove = nil; !tabToRemove &amp;&amp; i &lt; count; i++) {
+                            tab = [[newStyle tabStops] objectAtIndex:i];
+                            if ([tab location] &lt;= listLocation)
+                                tabToRemove = tab;
+                        }
+                        if (tabToRemove)
+                            [newStyle removeTabStop:tab];
+                        else
+                            break;
+                    }
+                    tab = [[PlatformNSTextTab alloc] initWithType:NSLeftTabStopType location:markerLocation];
+                    [newStyle addTabStop:tab];
+                    [tab release];
+#if PLATFORM(IOS)
+                    tab = [[PlatformNSTextTab alloc] initWithTextAlignment:NSTextAlignmentNatural location:listLocation options:nil];
+#else
+                    tab = [[PlatformNSTextTab alloc] initWithTextAlignment:NSNaturalTextAlignment location:listLocation options:nil];
+#endif
+                    [newStyle addTabStop:tab];
+                    [tab release];
+                    [_attrStr addAttribute:NSParagraphStyleAttributeName value:newStyle range:paragraphRange];
+                    [newStyle release];
+                    
+                    idx = NSMaxRange(paragraphRange);
+                } else {
+                    // skip any deeper-nested lists
+                    idx = NSMaxRange(styleRange);
+                }
+            }
+        }
+    }
+}
+
+void HTMLConverter::_exitElement(Element&amp; element, NSInteger depth, NSUInteger startIndex)
+{
+    String displayValue = _caches-&gt;propertyValueForNode(element, CSSPropertyDisplay);
+    NSRange range = NSMakeRange(startIndex, [_attrStr length] - startIndex);
+    if (range.length &gt; 0 &amp;&amp; element.hasTagName(aTag)) {
+        NSString *urlString = element.getAttribute(hrefAttr);
+        NSString *strippedString = [urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+        if (urlString &amp;&amp; [urlString length] &gt; 0 &amp;&amp; strippedString &amp;&amp; [strippedString length] &gt; 0 &amp;&amp; ![strippedString hasPrefix:@&quot;#&quot;]) {
+            NSURL *url = element.document().completeURL(stripLeadingAndTrailingHTMLSpaces(urlString));
+            if (!url)
+                url = element.document().completeURL(stripLeadingAndTrailingHTMLSpaces(strippedString));
+            if (!url)
+                url = [NSURL _web_URLWithString:strippedString relativeToURL:_baseURL];
+            [_attrStr addAttribute:NSLinkAttributeName value:url ? (id)url : (id)urlString range:range];
+        }
+    }
+    if (!_flags.reachedEnd &amp;&amp; _caches-&gt;isBlockElement(element)) {
+        [_writingDirectionArray removeAllObjects];
+        if (displayValue == &quot;table-cell&quot; &amp;&amp; [_textBlocks count] == 0) {
+            _newTabForElement(element);
+        } else if ([_textLists count] &gt; 0 &amp;&amp; displayValue == &quot;block&quot; &amp;&amp; !element.hasTagName(liTag) &amp;&amp; !element.hasTagName(ulTag) &amp;&amp; !element.hasTagName(olTag)) {
+            _newLineForElement(element);
+        } else {
+            _newParagraphForElement(element, element.tagName(), (range.length == 0), YES);
+        }
+    } else if ([_writingDirectionArray count] &gt; 0) {
+        String bidi = _caches-&gt;propertyValueForNode(element, CSSPropertyUnicodeBidi);
+        if (bidi == &quot;embed&quot; || bidi == &quot;bidi-override&quot;)
+            [_writingDirectionArray removeLastObject];
+    }
+    range = NSMakeRange(startIndex, [_attrStr length] - startIndex);
+    if (displayValue == &quot;table&quot; &amp;&amp; [_textTables count] &gt; 0) {
+        NSTextTable *key = [_textTables lastObject];
+        Element* footer = m_textTableFooters.get(key);
+        while ([_textTables count] &lt; [_textBlocks count] + 1)
+            [_textBlocks removeLastObject];
+        if (footer) {
+            _traverseFooterNode(*footer, depth + 1);
+            m_textTableFooters.remove(key);
+        }
+        [_textTables removeLastObject];
+        [_textTableSpacings removeLastObject];
+        [_textTablePaddings removeLastObject];
+        [_textTableRows removeLastObject];
+        [_textTableRowArrays removeLastObject];
+    } else if (displayValue == &quot;table-row&quot; &amp;&amp; [_textTables count] &gt; 0) {
+        NSTextTable *table = [_textTables lastObject];
+        NSTextTableBlock *block;
+        NSMutableArray *rowArray = [_textTableRowArrays lastObject], *previousRowArray;
+        NSUInteger i, count;
+        NSInteger numberOfColumns = [table numberOfColumns];
+        NSInteger openColumn;
+        NSInteger rowNumber = [[_textTableRows lastObject] integerValue];
+        do {
+            rowNumber++;
+            previousRowArray = rowArray;
+            rowArray = [NSMutableArray array];
+            count = [previousRowArray count];
+            for (i = 0; i &lt; count; i++) {
+                block = [previousRowArray objectAtIndex:i];
+                if ([block startingColumn] + [block columnSpan] &gt; numberOfColumns) numberOfColumns = [block startingColumn] + [block columnSpan];
+                if ([block startingRow] + [block rowSpan] &gt; rowNumber) [rowArray addObject:block];
+            }
+            count = [rowArray count];
+            openColumn = 0;
+            for (i = 0; i &lt; count; i++) {
+                block = [rowArray objectAtIndex:i];
+                if (openColumn &gt;= [block startingColumn] &amp;&amp; openColumn &lt; [block startingColumn] + [block columnSpan]) openColumn = [block startingColumn] + [block columnSpan];
+            }
+        } while (openColumn &gt;= numberOfColumns);
+        if ((NSUInteger)numberOfColumns &gt; [table numberOfColumns])
+            [table setNumberOfColumns:numberOfColumns];
+        [_textTableRows removeLastObject];
+        [_textTableRows addObject:[NSNumber numberWithInteger:rowNumber]];
+        [_textTableRowArrays removeLastObject];
+        [_textTableRowArrays addObject:rowArray];
+        if ([_textTableRowBackgroundColors count] &gt; 0)
+            [_textTableRowBackgroundColors removeLastObject];
+    } else if (displayValue == &quot;table-cell&quot; &amp;&amp; [_textBlocks count] &gt; 0) {
+        while ([_textTables count] &gt; [_textBlocks count]) {
+            [_textTables removeLastObject];
+            [_textTableSpacings removeLastObject];
+            [_textTablePaddings removeLastObject];
+            [_textTableRows removeLastObject];
+            [_textTableRowArrays removeLastObject];
+        }
+        [_textBlocks removeLastObject];
+    } else if ((element.hasTagName(ulTag) || element.hasTagName(olTag)) &amp;&amp; [_textLists count] &gt; 0) {
+        NSTextList *list = [_textLists lastObject];
+        _addMarkersToList(list, range);
+        [_textLists removeLastObject];
+    } else if (element.hasTagName(qTag)) {
+        _addQuoteForElement(element, NO, --_quoteLevel);
+    } else if (element.hasTagName(spanTag)) {
+        NSString *className = element.getAttribute(classAttr);
+        NSMutableString *mutableString;
+        NSUInteger i, count = 0;
+        unichar c;
+        if ([@&quot;Apple-converted-space&quot; isEqualToString:className]) {
+            mutableString = [_attrStr mutableString];
+            for (i = range.location; i &lt; NSMaxRange(range); i++) {
+                c = [mutableString characterAtIndex:i];
+                if (0xa0 == c)
+                    [mutableString replaceCharactersInRange:NSMakeRange(i, 1) withString:@&quot; &quot;];
+            }
+        } else if ([@&quot;Apple-converted-tab&quot; isEqualToString:className]) {
+            mutableString = [_attrStr mutableString];
+            for (i = range.location; i &lt; NSMaxRange(range); i++) {
+                NSRange rangeToReplace = NSMakeRange(NSNotFound, 0);
+                c = [mutableString characterAtIndex:i];
+                if (' ' == c || 0xa0 == c) {
+                    count++;
+                    if (count &gt;= 4 || i + 1 &gt;= NSMaxRange(range))
+                        rangeToReplace = NSMakeRange(i + 1 - count, count);
+                } else {
+                    if (count &gt; 0)
+                        rangeToReplace = NSMakeRange(i - count, count);
+                }
+                if (rangeToReplace.length &gt; 0) {
+                    [mutableString replaceCharactersInRange:rangeToReplace withString:@&quot;\t&quot;];
+                    range.length -= (rangeToReplace.length - 1);
+                    i -= (rangeToReplace.length - 1);
+                    if (NSMaxRange(rangeToReplace) &lt;= _domRangeStartIndex) {
+                        _domRangeStartIndex -= (rangeToReplace.length - 1);
+                    } else if (rangeToReplace.location &lt; _domRangeStartIndex) {
+                        _domRangeStartIndex = rangeToReplace.location;
+                    }
+                    count = 0;
+                }
+            }
+        }
+    }
+}
+
+void HTMLConverter::_processText(CharacterData&amp; characterData)
+{
+    NSUInteger textLength = [_attrStr length];
+    unichar lastChar = (textLength &gt; 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n';
+    BOOL suppressLeadingSpace = ((_flags.isSoft &amp;&amp; lastChar == ' ') || lastChar == '\n' || lastChar == '\r' || lastChar == '\t' || lastChar == NSParagraphSeparatorCharacter || lastChar == NSLineSeparatorCharacter || lastChar == NSFormFeedCharacter || lastChar == WebNextLineCharacter);
+    NSRange rangeToReplace = NSMakeRange(textLength, 0);
+    CFMutableStringRef mutstr = NULL;
+
+    String originalString = characterData.data();
+    unsigned startOffset = 0;
+    unsigned endOffset = originalString.length();
+    if (&amp;characterData == m_range-&gt;startContainer()) {
+        startOffset = m_range-&gt;startOffset();
+        _domRangeStartIndex = [_attrStr length];
+        _flags.reachedStart = YES;
+    }
+    if (&amp;characterData == m_range-&gt;endContainer()) {
+        endOffset = m_range-&gt;endOffset();
+        _flags.reachedEnd = YES;
+    }
+    if ((startOffset &gt; 0 || endOffset &lt; originalString.length()) &amp;&amp; endOffset &gt;= startOffset)
+        originalString = originalString.substring(startOffset, endOffset - startOffset);
+    String outputString = originalString;
+
+    // FIXME: Use RenderText's content instead.
+    bool wasSpace = false;
+    if (_caches-&gt;propertyValueForNode(characterData, CSSPropertyWhiteSpace).startsWith(&quot;pre&quot;)) {
+        if (textLength &amp;&amp; originalString.length() &amp;&amp; _flags.isSoft) {
+            unichar c = originalString.at(0);
+            if (c == '\n' || c == '\r' || c == NSParagraphSeparatorCharacter || c == NSLineSeparatorCharacter || c == NSFormFeedCharacter || c == WebNextLineCharacter)
+                rangeToReplace = NSMakeRange(textLength - 1, 1);
+        }
+    } else {
+        unsigned count = originalString.length();
+        bool wasLeading = true;
+        StringBuilder builder;
+        for (unsigned i = 0; i &lt; count; i++) {
+            UChar c = originalString.at(i);
+            bool isWhitespace = c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == 0xc || c == 0x200b;
+            if (isWhitespace)
+                wasSpace = (!wasLeading || !suppressLeadingSpace);
+            else {
+                if (wasSpace)
+                    builder.append(' ');
+                builder.append(c);
+                wasSpace = false;
+                wasLeading = false;
+            }
+        }
+        if (wasSpace)
+            builder.append(' ');
+        outputString = builder.toString();
+    }
+
+    if (outputString.length()) {
+        String textTransform = _caches-&gt;propertyValueForNode(characterData, CSSPropertyTextTransform);
+        if (textTransform.length()) {
+            if (textTransform == &quot;capitalize&quot;) {// FIXME: This is extremely inefficient.
+                NSString *temporaryString = outputString;
+                outputString = [temporaryString capitalizedString];
+            } else if (textTransform == &quot;uppercase&quot;)
+                outputString = outputString.upper();
+            else if (textTransform == &quot;lowercase&quot;)
+                outputString = outputString.lower();
+        }
+
+        [_attrStr replaceCharactersInRange:rangeToReplace withString:outputString];
+        rangeToReplace.length = outputString.length();
+        if (rangeToReplace.length)
+            [_attrStr setAttributes:aggregatedAttributesForAncestors(characterData) range:rangeToReplace];
+        _flags.isSoft = wasSpace;
+    }
+    if (mutstr)
+        CFRelease(mutstr);
+}
+
+void HTMLConverter::_traverseNode(Node&amp; node, unsigned depth, bool embedded)
+{
+    if (_flags.reachedEnd)
+        return;
+    if (!_flags.reachedStart &amp;&amp; !_caches-&gt;isAncestorsOfStartToBeConverted(node))
+        return;
+
+    unsigned startOffset = 0;
+    unsigned endOffset = UINT_MAX;
+    bool isStart = false;
+    bool isEnd = false;
+    if (&amp;node == m_range-&gt;startContainer()) {
+        startOffset = m_range-&gt;startOffset();
+        isStart = true;
+        _flags.reachedStart = YES;
+    }
+    if (&amp;node == m_range-&gt;endContainer()) {
+        endOffset = m_range-&gt;endOffset();
+        isEnd = true;
+    }
+    
+    if (node.isDocumentNode() || node.isDocumentFragment()) {
+        Node* child = node.firstChild();
+        for (NSUInteger i = 0; child; i++) {
+            if (isStart &amp;&amp; i == startOffset)
+                _domRangeStartIndex = [_attrStr length];
+            if ((!isStart || startOffset &lt;= i) &amp;&amp; (!isEnd || endOffset &gt; i))
+                _traverseNode(*child, depth + 1, embedded);
+            if (isEnd &amp;&amp; i + 1 &gt;= endOffset)
+                _flags.reachedEnd = YES;
+            if (_flags.reachedEnd)
+                break;
+            child = child-&gt;nextSibling();
+        }
+    } else if (node.isElementNode()) {
+        Element&amp; element = toElement(node);
+        if (_enterElement(element, embedded)) {
+            NSUInteger startIndex = [_attrStr length];
+            if (_processElement(element, depth)) {
+                Node* child = node.firstChild();
+                for (NSUInteger i = 0; child; i++) {
+                    if (isStart &amp;&amp; i == startOffset)
+                        _domRangeStartIndex = [_attrStr length];
+                    if ((!isStart || startOffset &lt;= i) &amp;&amp; (!isEnd || endOffset &gt; i))
+                        _traverseNode(*child, depth + 1, embedded);
+                    if (isEnd &amp;&amp; i + 1 &gt;= endOffset)
+                        _flags.reachedEnd = YES;
+                    if (_flags.reachedEnd)
+                        break;
+                    child = child-&gt;nextSibling();
+                }
+                _exitElement(element, depth, startIndex);
+            }
+        }
+    } else if (node.isCharacterDataNode())
+        _processText(toCharacterData(node));
+
+    if (isEnd)
+        _flags.reachedEnd = YES;
+}
+
+void HTMLConverter::_traverseFooterNode(Element&amp; element, unsigned depth)
+{
+    if (_flags.reachedEnd)
+        return;
+    if (!_flags.reachedStart &amp;&amp; !_caches-&gt;isAncestorsOfStartToBeConverted(element))
+        return;
+
+    unsigned startOffset = 0;
+    unsigned endOffset = UINT_MAX;
+    bool isStart = false;
+    bool isEnd = false;
+    if (&amp;element == m_range-&gt;startContainer()) {
+        startOffset = m_range-&gt;startOffset();
+        isStart = true;
+        _flags.reachedStart = YES;
+    }
+    if (&amp;element == m_range-&gt;endContainer()) {
+        endOffset = m_range-&gt;endOffset();
+        isEnd = true;
+    }
+    
+    if (_enterElement(element, YES)) {
+        NSUInteger startIndex = [_attrStr length];
+        if (_processElement(element, depth)) {
+            Node* child = element.firstChild();
+            for (NSUInteger i = 0; child; i++) {
+                if (isStart &amp;&amp; i == startOffset)
+                    _domRangeStartIndex = [_attrStr length];
+                if ((!isStart || startOffset &lt;= i) &amp;&amp; (!isEnd || endOffset &gt; i))
+                    _traverseNode(*child, depth + 1, true /* embedded */);
+                if (isEnd &amp;&amp; i + 1 &gt;= endOffset)
+                    _flags.reachedEnd = YES;
+                if (_flags.reachedEnd)
+                    break;
+                child = child-&gt;nextSibling();
+            }
+            _exitElement(element, depth, startIndex);
+        }
+    }
+    if (isEnd)
+        _flags.reachedEnd = YES;
+}
+
+void HTMLConverter::_adjustTrailingNewline()
+{
+    NSUInteger textLength = [_attrStr length];
+    unichar lastChar = (textLength &gt; 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : 0;
+    BOOL alreadyHasTrailingNewline = (lastChar == '\n' || lastChar == '\r' || lastChar == NSParagraphSeparatorCharacter || lastChar == NSLineSeparatorCharacter || lastChar == WebNextLineCharacter);
+    if (_flags.hasTrailingNewline &amp;&amp; !alreadyHasTrailingNewline)
+        [_attrStr replaceCharactersInRange:NSMakeRange(textLength, 0) withString:@&quot;\n&quot;];
+}
+
+Node* HTMLConverterCaches::cacheAncestorsOfStartToBeConverted(const Range&amp; range)
+{
+    Node* commonAncestor = range.commonAncestorContainer(ASSERT_NO_EXCEPTION);
+    Node* ancestor = range.startContainer();
+
+    while (ancestor) {
+        m_ancestorsUnderCommonAncestor.add(ancestor);
+        if (ancestor == commonAncestor)
+            break;
+        ancestor = ancestor-&gt;parentNode();
+    }
+
+    return commonAncestor;
+}
+
+#if !PLATFORM(IOS)
+
+static NSFileWrapper *fileWrapperForURL(DocumentLoader *dataSource, NSURL *URL)
+{
+    if ([URL isFileURL])
+        return [[[NSFileWrapper alloc] initWithURL:[URL URLByResolvingSymlinksInPath] options:0 error:nullptr] autorelease];
+
+    RefPtr&lt;ArchiveResource&gt; resource = dataSource-&gt;subresource(URL);
+    if (resource) {
+        NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:resource-&gt;data()-&gt;createNSData().get()] autorelease];
+        NSString *filename = resource-&gt;response().suggestedFilename();
+        if (!filename || ![filename length])
+            filename = suggestedFilenameWithMIMEType(resource-&gt;url(), resource-&gt;mimeType());
+        [wrapper setPreferredFilename:filename];
+        return wrapper;
+    }
+    
+    NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];
+
+    NSCachedURLResponse *cachedResponse = [[NSURLCache sharedURLCache] cachedResponseForRequest:request];
+    [request release];
+    
+    if (cachedResponse) {
+        NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:[cachedResponse data]] autorelease];
+        [wrapper setPreferredFilename:[[cachedResponse response] suggestedFilename]];
+        return wrapper;
+    }
+    
+    return nil;
+}
+
+static NSFileWrapper *fileWrapperForElement(Element* element)
+{
+    NSFileWrapper *wrapper = nil;
+    
+    const AtomicString&amp; attr = element-&gt;getAttribute(srcAttr);
+    if (!attr.isEmpty()) {
+        NSURL *URL = element-&gt;document().completeURL(attr);
+        if (DocumentLoader* loader = element-&gt;document().loader())
+            wrapper = fileWrapperForURL(loader, URL);
+    }
+    if (!wrapper) {
+        RenderImage* renderer = toRenderImage(element-&gt;renderer());
+        if (renderer-&gt;cachedImage() &amp;&amp; !renderer-&gt;cachedImage()-&gt;errorOccurred()) {
+            wrapper = [[NSFileWrapper alloc] initRegularFileWithContents:(NSData *)(renderer-&gt;cachedImage()-&gt;imageForRenderer(renderer)-&gt;getTIFFRepresentation())];
+            [wrapper setPreferredFilename:@&quot;image.tiff&quot;];
+            [wrapper autorelease];
+        }
+    }
+
+    return wrapper;
+}
+
+#endif
+
+namespace WebCore {
+    
+// This function supports more HTML features than the editing variant below, such as tables.
+NSAttributedString *attributedStringFromRange(Range&amp; range)
+{
+    HTMLConverter converter(range);
+    return converter.convert();
+}
+    
+#if !PLATFORM(IOS)
+// This function uses TextIterator, which makes offsets in its result compatible with HTML editing.
+NSAttributedString *editingAttributedStringFromRange(Range&amp; range)
+{
+    NSFontManager *fontManager = [NSFontManager sharedFontManager];
+    NSMutableAttributedString *string = [[NSMutableAttributedString alloc] init];
+    NSUInteger stringLength = 0;
+    RetainPtr&lt;NSMutableDictionary&gt; attrs = adoptNS([[NSMutableDictionary alloc] init]);
+
+    for (TextIterator it(&amp;range); !it.atEnd(); it.advance()) {
+        RefPtr&lt;Range&gt; currentTextRange = it.range();
+        Node* startContainer = currentTextRange-&gt;startContainer();
+        Node* endContainer = currentTextRange-&gt;endContainer();
+        int startOffset = currentTextRange-&gt;startOffset();
+        int endOffset = currentTextRange-&gt;endOffset();
+        
+        if (startContainer == endContainer &amp;&amp; (startOffset == endOffset - 1)) {
+            Node* node = startContainer-&gt;childNode(startOffset);
+            if (node &amp;&amp; node-&gt;hasTagName(imgTag)) {
+                NSFileWrapper* fileWrapper = fileWrapperForElement(toElement(node));
+                NSTextAttachment* attachment = [[NSTextAttachment alloc] initWithFileWrapper:fileWrapper];
+                [string appendAttributedString:[NSAttributedString attributedStringWithAttachment:attachment]];
+                [attachment release];
+            }
+        }
+
+        int currentTextLength = it.text().length();
+        if (!currentTextLength)
+            continue;
+
+        RenderObject* renderer = startContainer-&gt;renderer();
+        ASSERT(renderer);
+        if (!renderer)
+            continue;
+        const RenderStyle&amp; style = renderer-&gt;style();
+        if (style.textDecorationsInEffect() &amp; TextDecorationUnderline)
+            [attrs.get() setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName];
+        if (style.textDecorationsInEffect() &amp; TextDecorationLineThrough)
+            [attrs.get() setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSStrikethroughStyleAttributeName];
+        if (NSFont *font = style.font().primaryFont()-&gt;getNSFont())
+            [attrs.get() setObject:font forKey:NSFontAttributeName];
+        else
+            [attrs.get() setObject:[fontManager convertFont:WebDefaultFont() toSize:style.font().primaryFont()-&gt;platformData().size()] forKey:NSFontAttributeName];
+        if (style.visitedDependentColor(CSSPropertyColor).alpha())
+            [attrs.get() setObject:nsColor(style.visitedDependentColor(CSSPropertyColor)) forKey:NSForegroundColorAttributeName];
+        else
+            [attrs.get() removeObjectForKey:NSForegroundColorAttributeName];
+        if (style.visitedDependentColor(CSSPropertyBackgroundColor).alpha())
+            [attrs.get() setObject:nsColor(style.visitedDependentColor(CSSPropertyBackgroundColor)) forKey:NSBackgroundColorAttributeName];
+        else
+            [attrs.get() removeObjectForKey:NSBackgroundColorAttributeName];
+
+        [string replaceCharactersInRange:NSMakeRange(stringLength, 0) withString:it.text().createNSStringWithoutCopying().get()];
+        [string setAttributes:attrs.get() range:NSMakeRange(stringLength, currentTextLength)];
+        stringLength += currentTextLength;
+    }
+
+    return [string autorelease];
+}
+#endif
+    
+}
</ins></span></pre>
</div>
</div>

</body>
</html>