<!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>[166147] 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/166147">166147</a></dd>
<dt>Author</dt> <dd>weinig@apple.com</dd>
<dt>Date</dt> <dd>2014-03-23 15:14:20 -0700 (Sun, 23 Mar 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>Move HTMLConverter from platform/mac to editing/cocoa.
Rubber-stamped by Darin Adler.
* WebCore.xcodeproj/project.pbxproj:
* editing/cocoa: Added.
* editing/cocoa/HTMLConverter.h: Copied from platform/mac/HTMLConverter.h.
* editing/cocoa/HTMLConverter.mm: Copied from platform/mac/HTMLConverter.mm.
* platform/mac/HTMLConverter.h: Removed.
* platform/mac/HTMLConverter.mm: Removed.</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>trunk/Source/WebCore/editing/cocoa/</li>
<li><a href="#trunkSourceWebCoreeditingcocoaHTMLConverterh">trunk/Source/WebCore/editing/cocoa/HTMLConverter.h</a></li>
<li><a href="#trunkSourceWebCoreeditingcocoaHTMLConvertermm">trunk/Source/WebCore/editing/cocoa/HTMLConverter.mm</a></li>
</ul>
<h3>Removed Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreplatformmacHTMLConverterh">trunk/Source/WebCore/platform/mac/HTMLConverter.h</a></li>
<li><a href="#trunkSourceWebCoreplatformmacHTMLConvertermm">trunk/Source/WebCore/platform/mac/HTMLConverter.mm</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (166146 => 166147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-03-23 21:47:52 UTC (rev 166146)
+++ trunk/Source/WebCore/ChangeLog        2014-03-23 22:14:20 UTC (rev 166147)
</span><span class="lines">@@ -1,5 +1,18 @@
</span><span class="cx"> 2014-03-23 Sam Weinig <sam@webkit.org>
</span><span class="cx">
</span><ins>+ Move HTMLConverter from platform/mac to editing/cocoa.
+
+ Rubber-stamped by Darin Adler.
+
+ * WebCore.xcodeproj/project.pbxproj:
+ * editing/cocoa: Added.
+ * editing/cocoa/HTMLConverter.h: Copied from platform/mac/HTMLConverter.h.
+ * editing/cocoa/HTMLConverter.mm: Copied from platform/mac/HTMLConverter.mm.
+ * platform/mac/HTMLConverter.h: Removed.
+ * platform/mac/HTMLConverter.mm: Removed.
+
+2014-03-23 Sam Weinig <sam@webkit.org>
+
</ins><span class="cx"> Simplify the HTMLConverter interface (Part 2)
</span><span class="cx"> https://bugs.webkit.org/show_bug.cgi?id=130654
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (166146 => 166147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2014-03-23 21:47:52 UTC (rev 166146)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj        2014-03-23 22:14:20 UTC (rev 166147)
</span><span class="lines">@@ -2034,7 +2034,6 @@
</span><span class="cx">                 5B7A208D2E12979B4AE19DE6 /* RenderMathMLSpace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DBFCB0EBFF5CD77EBEB35395 /* RenderMathMLSpace.cpp */; };
</span><span class="cx">                 5D21A80213ECE5DF00BB7064 /* WebVTTParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5D21A80013ECE5DF00BB7064 /* WebVTTParser.cpp */; };
</span><span class="cx">                 5D21A80313ECE5DF00BB7064 /* WebVTTParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D21A80113ECE5DF00BB7064 /* WebVTTParser.h */; };
</span><del>-                5D4F51DF132725480016F541 /* HTMLConverter.mm in Sources */ = {isa = PBXBuildFile; fileRef = C5392D341326AD0100043D35 /* HTMLConverter.mm */; };
</del><span class="cx">                 5D874F130D161D3200796C3B /* NetscapePlugInStreamLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93E227DD0AF589AD00D48324 /* NetscapePlugInStreamLoader.cpp */; };
</span><span class="cx">                 5D87BB8311E3ED8600702B6F /* ExportFileGenerator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5D87BB8211E3ED8600702B6F /* ExportFileGenerator.cpp */; };
</span><span class="cx">                 5D8C4DBF1428222C0026CE72 /* DisplaySleepDisabler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5D8C4DBD1428222C0026CE72 /* DisplaySleepDisabler.cpp */; };
</span><span class="lines">@@ -2320,6 +2319,8 @@
</span><span class="cx">                 7BE7427381FA906FBB4F0F2C /* JSSVGGraphicsElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 950C4C02BED8936F818E2F99 /* JSSVGGraphicsElement.h */; };
</span><span class="cx">                 7C2BDD3D17C7F98C0038FF15 /* JSDOMGlobalObjectTask.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C2BDD3B17C7F98B0038FF15 /* JSDOMGlobalObjectTask.cpp */; };
</span><span class="cx">                 7C2BDD3E17C7F98C0038FF15 /* JSDOMGlobalObjectTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 7C2BDD3C17C7F98B0038FF15 /* JSDOMGlobalObjectTask.h */; };
</span><ins>+                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 */; };
</ins><span class="cx">                 7C4902A218B825F8007D9298 /* DOMWheelEventInternal.h in Copy Generated Headers */ = {isa = PBXBuildFile; fileRef = 85989DCA0ACC8BBD00A0BC51 /* DOMWheelEventInternal.h */; };
</span><span class="cx">                 7C522D4B15B477E8009B7C95 /* InspectorOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C522D4915B477E8009B7C95 /* InspectorOverlay.cpp */; };
</span><span class="cx">                 7C5343FC17B74B63004232F0 /* JSMediaQueryListListener.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7C5343FA17B74B63004232F0 /* JSMediaQueryListListener.cpp */; };
</span><span class="lines">@@ -5865,7 +5866,6 @@
</span><span class="cx">                 E1A1470811102B1500EEC0F3 /* ContainerNodeAlgorithms.h in Headers */ = {isa = PBXBuildFile; fileRef = E1A1470711102B1500EEC0F3 /* ContainerNodeAlgorithms.h */; };
</span><span class="cx">                 E1A3162D134BC32D007C9A4F /* WebNSAttributedStringExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = E1A3162B134BC32D007C9A4F /* WebNSAttributedStringExtras.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 E1A3162E134BC32D007C9A4F /* WebNSAttributedStringExtras.mm in Sources */ = {isa = PBXBuildFile; fileRef = E1A3162C134BC32D007C9A4F /* WebNSAttributedStringExtras.mm */; };
</span><del>-                E1A31663134BCAE8007C9A4F /* HTMLConverter.h in Headers */ = {isa = PBXBuildFile; fileRef = C5392D331326AD0100043D35 /* HTMLConverter.h */; settings = {ATTRIBUTES = (Private, ); }; };
</del><span class="cx">                 E1A5F99B0E7EAA2500AF85EA /* JSMessageChannelCustom.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1A5F99A0E7EAA2500AF85EA /* JSMessageChannelCustom.cpp */; };
</span><span class="cx">                 E1A643F20EC0972500779668 /* WorkerScriptController.h in Headers */ = {isa = PBXBuildFile; fileRef = E1A643F10EC0972500779668 /* WorkerScriptController.h */; };
</span><span class="cx">                 E1A643FD0EC097A000779668 /* WorkerScriptController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E1A643FC0EC097A000779668 /* WorkerScriptController.cpp */; };
</span><span class="lines">@@ -9335,6 +9335,8 @@
</span><span class="cx">                 7AF9B20B18CFB5F300C64BEF /* JSVTTRegionList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSVTTRegionList.h; sourceTree = "<group>"; };
</span><span class="cx">                 7C2BDD3B17C7F98B0038FF15 /* JSDOMGlobalObjectTask.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDOMGlobalObjectTask.cpp; sourceTree = "<group>"; };
</span><span class="cx">                 7C2BDD3C17C7F98B0038FF15 /* JSDOMGlobalObjectTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSDOMGlobalObjectTask.h; sourceTree = "<group>"; };
</span><ins>+                7C3E510818DF8F3500C112F7 /* HTMLConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLConverter.h; sourceTree = "<group>"; };
+                7C3E510918DF8F3500C112F7 /* HTMLConverter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = HTMLConverter.mm; sourceTree = "<group>"; };
</ins><span class="cx">                 7C522D4915B477E8009B7C95 /* InspectorOverlay.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InspectorOverlay.cpp; sourceTree = "<group>"; };
</span><span class="cx">                 7C522D4A15B478B2009B7C95 /* InspectorOverlay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InspectorOverlay.h; sourceTree = "<group>"; };
</span><span class="cx">                 7C5343FA17B74B63004232F0 /* JSMediaQueryListListener.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSMediaQueryListListener.cpp; sourceTree = "<group>"; };
</span><span class="lines">@@ -12731,8 +12733,6 @@
</span><span class="cx">                 C5160EE81004543A00A7CEE2 /* StorageAreaImpl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StorageAreaImpl.cpp; sourceTree = "<group>"; };
</span><span class="cx">                 C5160EE91004543A00A7CEE2 /* StorageAreaImpl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StorageAreaImpl.h; sourceTree = "<group>"; };
</span><span class="cx">                 C5278B0B17F212EA003A2998 /* PlatformPasteboardIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = PlatformPasteboardIOS.mm; path = ios/PlatformPasteboardIOS.mm; sourceTree = "<group>"; };
</span><del>-                C5392D331326AD0100043D35 /* HTMLConverter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTMLConverter.h; sourceTree = "<group>"; };
-                C5392D341326AD0100043D35 /* HTMLConverter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = HTMLConverter.mm; sourceTree = "<group>"; };
</del><span class="cx">                 C544274911A57E7A0063A749 /* DOMStringList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMStringList.h; sourceTree = "<group>"; };
</span><span class="cx">                 C544274A11A57E7A0063A749 /* DOMStringList.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DOMStringList.idl; sourceTree = "<group>"; };
</span><span class="cx">                 C55610F011A704EB00B82D27 /* DOMStringList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMStringList.cpp; sourceTree = "<group>"; };
</span><span class="lines">@@ -16074,8 +16074,6 @@
</span><span class="cx">                                 E1BA66F01742BD8600C20251 /* DynamicLinkerInterposing.h */,
</span><span class="cx">                                 1CA19E030DC255950065A994 /* EventLoopMac.mm */,
</span><span class="cx">                                 514B3F750C722055000530DF /* FileSystemMac.mm */,
</span><del>-                                C5392D331326AD0100043D35 /* HTMLConverter.h */,
-                                C5392D341326AD0100043D35 /* HTMLConverter.mm */,
</del><span class="cx">                                 935C476E09AC4D7300A6AAB4 /* KeyEventMac.mm */,
</span><span class="cx">                                 521D46F511AEC98100514613 /* KillRingMac.mm */,
</span><span class="cx">                                 9352084409BD43B900F2038D /* Language.mm */,
</span><span class="lines">@@ -16364,6 +16362,15 @@
</span><span class="cx">                         tabWidth = 4;
</span><span class="cx">                         usesTabs = 0;
</span><span class="cx">                 };
</span><ins>+                7C3E510718DF8F1200C112F7 /* cocoa */ = {
+                        isa = PBXGroup;
+                        children = (
+                                7C3E510818DF8F3500C112F7 /* HTMLConverter.h */,
+                                7C3E510918DF8F3500C112F7 /* HTMLConverter.mm */,
+                        );
+                        path = cocoa;
+                        sourceTree = "<group>";
+                };
</ins><span class="cx">                 7C74D43018823A4200E5ED57 /* icu */ = {
</span><span class="cx">                         isa = PBXGroup;
</span><span class="cx">                         children = (
</span><span class="lines">@@ -17005,6 +17012,7 @@
</span><span class="cx">                 93309D86099E64910056E581 /* editing */ = {
</span><span class="cx">                         isa = PBXGroup;
</span><span class="cx">                         children = (
</span><ins>+                                7C3E510718DF8F1200C112F7 /* cocoa */,
</ins><span class="cx">                                 443292C10EBA6D7300E62016 /* ios */,
</span><span class="cx">                                 ED501DC90B249F3900AE18D9 /* mac */,
</span><span class="cx">                                 CE08C3CF152B599A0021B8C2 /* AlternativeTextController.cpp */,
</span><span class="lines">@@ -23266,6 +23274,7 @@
</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><ins>+                                7C3E510A18DF8F3500C112F7 /* HTMLConverter.h in Headers */,
</ins><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">@@ -23911,7 +23920,6 @@
</span><span class="cx">                                 996231F318D18AC300C03FDA /* InspectorWebBackendCommands.js in Headers */,
</span><span class="cx">                                 A8DF3FD0097FA0FC0052981B /* HTMLCollection.h in Headers */,
</span><span class="cx">                                 977B3865122883E900B81FF8 /* HTMLConstructionSite.h in Headers */,
</span><del>-                                E1A31663134BCAE8007C9A4F /* HTMLConverter.h in Headers */,
</del><span class="cx">                                 F5C041DB0FFCA7CE00839D4A /* HTMLDataListElement.h in Headers */,
</span><span class="cx">                                 D359D78A129CA2710006E5D2 /* HTMLDetailsElement.h in Headers */,
</span><span class="cx">                                 A8EA79FA0A1916DF00A8EF5F /* HTMLDirectoryElement.h in Headers */,
</span><span class="lines">@@ -27321,7 +27329,6 @@
</span><span class="cx">                                 93F19AFD08245E59001E9ABC /* HTMLCanvasElement.cpp in Sources */,
</span><span class="cx">                                 A8DF3FD1097FA0FC0052981B /* HTMLCollection.cpp in Sources */,
</span><span class="cx">                                 977B3864122883E900B81FF8 /* HTMLConstructionSite.cpp in Sources */,
</span><del>-                                5D4F51DF132725480016F541 /* HTMLConverter.mm in Sources */,
</del><span class="cx">                                 F5C041DA0FFCA7CE00839D4A /* HTMLDataListElement.cpp in Sources */,
</span><span class="cx">                                 D359D789129CA2710006E5D2 /* HTMLDetailsElement.cpp in Sources */,
</span><span class="cx">                                 A8EA79F90A1916DF00A8EF5F /* HTMLDirectoryElement.cpp in Sources */,
</span><span class="lines">@@ -28425,6 +28432,7 @@
</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><ins>+                                7C3E510B18DF8F3500C112F7 /* HTMLConverter.mm in Sources */,
</ins><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></pre></div>
<a id="trunkSourceWebCoreeditingcocoaHTMLConverterhfromrev166145trunkSourceWebCoreplatformmacHTMLConverterh"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebCore/editing/cocoa/HTMLConverter.h (from rev 166145, trunk/Source/WebCore/platform/mac/HTMLConverter.h) (0 => 166147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/cocoa/HTMLConverter.h         (rev 0)
+++ trunk/Source/WebCore/editing/cocoa/HTMLConverter.h        2014-03-23 22:14:20 UTC (rev 166147)
</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;
+
+NSAttributedString *attributedStringFromRange(Range&);
+#if !PLATFORM(IOS)
+NSAttributedString *editingAttributedStringFromRange(Range&);
+#endif
+
+}
+
+#endif // HTMLConverter_h
</ins></span></pre></div>
<a id="trunkSourceWebCoreeditingcocoaHTMLConvertermmfromrev166145trunkSourceWebCoreplatformmacHTMLConvertermm"></a>
<div class="copfile"><h4>Copied: trunk/Source/WebCore/editing/cocoa/HTMLConverter.mm (from rev 166145, trunk/Source/WebCore/platform/mac/HTMLConverter.mm) (0 => 166147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/editing/cocoa/HTMLConverter.mm         (rev 0)
+++ trunk/Source/WebCore/editing/cocoa/HTMLConverter.mm        2014-03-23 22:14:20 UTC (rev 166147)
</span><span class="lines">@@ -0,0 +1,2648 @@
</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 "config.h"
+#import "HTMLConverter.h"
+
+#import "ArchiveResource.h"
+#import "CachedImage.h"
+#import "ColorMac.h"
+#import "CSSComputedStyleDeclaration.h"
+#import "CSSParser.h"
+#import "CSSPrimitiveValue.h"
+#import "Document.h"
+#import "DocumentLoader.h"
+#import "DOMCSSPrimitiveValueInternal.h"
+#import "DOMDocumentInternal.h"
+#import "DOMElementInternal.h"
+#import "DOMHTMLTableCellElement.h"
+#import "DOMNodeInternal.h"
+#import "DOMPrivate.h"
+#import "DOMRGBColorInternal.h"
+#import "DOMRangeInternal.h"
+#import "Element.h"
+#import "Font.h"
+#import "Frame.h"
+#import "FrameLoader.h"
+#import "HTMLElement.h"
+#import "HTMLNames.h"
+#import "HTMLParserIdioms.h"
+#import "LoaderNSURLExtras.h"
+#import "RGBColor.h"
+#import "RenderImage.h"
+#import "SoftLinking.h"
+#import "StyleProperties.h"
+#import "StyledElement.h"
+#import "TextIterator.h"
+#import <objc/runtime.h>
+#import <wtf/ASCIICType.h>
+
+#if PLATFORM(IOS)
+
+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 = @"NSSuperscript";
+#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 << 0
+ UIFontTraitBold = 0x00000002, // 1 << 1
+ UIFontTraitThin = (1 << 2),
+ UIFontTraitLight = (1 << 3),
+ UIFontTraitUltraLight = (1 << 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 << 1),
+ NSTextWritingDirectionOverride = (1 << 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;
+
+class HTMLConverterCaches {
+public:
+ String propertyValueForNode(Node&, CSSPropertyID );
+ bool floatPropertyValueForNode(Node&, CSSPropertyID, float&);
+ Color colorPropertyValueForNode(Node&, CSSPropertyID);
+
+ bool isBlockElement(Element&);
+ bool elementHasOwnBackgroundColor(Element&);
+
+ PassRefPtr<CSSValue> computedStylePropertyForElement(Element&, CSSPropertyID);
+ PassRefPtr<CSSValue> inlineStylePropertyForElement(Element&, CSSPropertyID);
+
+private:
+ HashMap<Element*, std::unique_ptr<ComputedStyleExtractor>> m_computedStyles;
+};
+
+@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
+
+@interface WebHTMLConverter : NSObject {
+ NSMutableAttributedString *_attrStr;
+ NSMutableDictionary *_documentAttrs;
+ NSURL *_baseURL;
+ DOMDocument *_document;
+ DOMRange *_domRange;
+ NSMutableArray *_domStartAncestors;
+ WebCore::DocumentLoader *_dataSource;
+ NSString *_standardFontFamily;
+ CGFloat _textSizeMultiplier;
+ CGFloat _webViewTextSizeMultiplier;
+ CGFloat _defaultTabInterval;
+ CGFloat _defaultFontSize;
+ CGFloat _minimumFontSize;
+ NSMutableArray *_textLists;
+ NSMutableArray *_textBlocks;
+ NSMutableArray *_textTables;
+ NSMutableDictionary *_textTableFooters;
+ NSMutableArray *_textTableSpacings;
+ NSMutableArray *_textTablePaddings;
+ NSMutableArray *_textTableRows;
+ NSMutableArray *_textTableRowArrays;
+ NSMutableArray *_textTableRowBackgroundColors;
+ NSMutableDictionary *_colorsForNodes;
+ NSMutableDictionary *_attributesForElements;
+ NSMutableDictionary *_fontCache;
+ NSMutableArray *_writingDirectionArray;
+ NSUInteger _domRangeStartIndex;
+ NSInteger _indexingLimit;
+ NSUInteger _thumbnailLimit;
+ NSInteger _errorCode;
+ NSInteger _quoteLevel;
+
+ std::unique_ptr<HTMLConverterCaches> _caches;
+
+ struct {
+ unsigned int isSoft:1;
+ unsigned int reachedStart:1;
+ unsigned int reachedEnd:1;
+ unsigned int isIndexing:1;
+ unsigned int isTesting:1;
+ unsigned int hasTrailingNewline:1;
+ unsigned int pad:26;
+ } _flags;
+}
+
++ (NSAttributedString *)attributedStringFromRange:(Range*)range;
+#if !PLATFORM(IOS)
++ (NSAttributedString *)editingAttributedStringFromRange:(Range*)range;
+#endif
+@end
+
+@interface WebHTMLConverter(WebHTMLConverterInternal)
+
+- (id)init;
+- (id)initWithDOMRange:(DOMRange *)domRange;
+- (NSAttributedString *)attributedString;
+
+- (NSString *)_stringForNode:(DOMNode *)node property:(CSSPropertyID)propertyId;
+- (PlatformColor *)_colorForNode:(DOMNode *)node property:(CSSPropertyID)propertyId;
+- (BOOL)_getFloat:(CGFloat *)val forNode:(DOMNode *)node property:(CSSPropertyID)propertyId;
+
+- (void)_traverseNode:(DOMNode *)node depth:(NSInteger)depth embedded:(BOOL)embedded;
+- (void)_traverseFooterNode:(DOMNode *)node depth:(NSInteger)depth;
+
+@end
+
+@implementation WebHTMLConverter
+
+#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:@"Helvetica" 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:@" " options:NSBackwardsSearch];
+ NSRange dividingDashRange = [fontName rangeOfString:@"-" options:NSBackwardsSearch];
+ dividingRange = (0 < dividingSpaceRange.length && 0 < dividingDashRange.length) ? (dividingSpaceRange.location > dividingDashRange.location ? dividingSpaceRange : dividingDashRange) : (0 < dividingSpaceRange.length ? dividingSpaceRange : dividingDashRange);
+
+ while (dividingRange.length > 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 && [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 < [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:@" " options:NSBackwardsSearch];
+ dividingDashRange = [familyName rangeOfString:@"-" options:NSBackwardsSearch];
+ dividingRange = (0 < dividingSpaceRange.length && 0 < dividingDashRange.length) ? (dividingSpaceRange.location > dividingDashRange.location ? dividingSpaceRange : dividingDashRange) : (0 < dividingSpaceRange.length ? dividingSpaceRange : dividingDashRange);
+ }
+ }
+ }
+#if PLATFORM(IOS)
+ if (!font)
+ font = [PlatformFontClass systemFontOfSize:size];
+#else
+ if (!font)
+ font = [NSFont fontWithName:@"Times" 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;
+}
+
++ (NSParagraphStyle *)defaultParagraphStyle
+{
+ static NSMutableParagraphStyle *defaultParagraphStyle = nil;
+ if (!defaultParagraphStyle) {
+ defaultParagraphStyle = [[PlatformNSParagraphStyle defaultParagraphStyle] mutableCopy];
+ [defaultParagraphStyle setDefaultTabInterval:36];
+ [defaultParagraphStyle setTabStops:[NSArray array]];
+ }
+ return defaultParagraphStyle;
+}
+
+- (NSArray *)_childrenForNode:(DOMNode *)node
+{
+ NSMutableArray *array = [NSMutableArray array];
+ DOMNode *child = [node firstChild];
+ while (child) {
+ [array addObject:child];
+ child = [child nextSibling];
+ }
+ return array;
+}
+
+PassRefPtr<CSSValue> HTMLConverterCaches::computedStylePropertyForElement(Element& element, CSSPropertyID propertyId)
+{
+ if (propertyId == CSSPropertyInvalid)
+ return nullptr;
+
+ auto result = m_computedStyles.add(&element, nullptr);
+ if (result.isNewEntry)
+ result.iterator->value = std::make_unique<ComputedStyleExtractor>(&element, true);
+ ComputedStyleExtractor& computedStyle = *result.iterator->value;
+ return computedStyle.propertyValue(propertyId);
+}
+
+PassRefPtr<CSSValue> HTMLConverterCaches::inlineStylePropertyForElement(Element& element, CSSPropertyID propertyId)
+{
+ if (propertyId == CSSPropertyInvalid || !element.isStyledElement())
+ return nullptr;
+ const StyleProperties* properties = toStyledElement(element).inlineStyle();
+ if (!properties)
+ return nullptr;
+ return properties->getPropertyCSSValue(propertyId);
+}
+
+static bool stringFromCSSValue(CSSValue& value, String& 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& node, CSSPropertyID propertyId)
+{
+ if (!node.isElementNode()) {
+ if (Node* parent = node.parentNode())
+ return propertyValueForNode(*parent, propertyId);
+ return String();
+ }
+
+ bool inherit = false;
+ Element& element = toElement(node);
+ if (RefPtr<CSSValue> value = computedStylePropertyForElement(element, propertyId)) {
+ String result;
+ if (stringFromCSSValue(*value, result))
+ return result;
+ }
+
+ if (RefPtr<CSSValue> value = inlineStylePropertyForElement(element, propertyId)) {
+ String result;
+ if (value->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 "none";
+ 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 "block";
+ else if (element.hasTagName(liTag))
+ return "list-item";
+ else if (element.hasTagName(tableTag))
+ return "table";
+ else if (element.hasTagName(trTag))
+ return "table-row";
+ else if (element.hasTagName(thTag) || element.hasTagName(tdTag))
+ return "table-cell";
+ else if (element.hasTagName(theadTag))
+ return "table-header-group";
+ else if (element.hasTagName(tbodyTag))
+ return "table-row-group";
+ else if (element.hasTagName(tfootTag))
+ return "table-footer-group";
+ else if (element.hasTagName(colTag))
+ return "table-column";
+ else if (element.hasTagName(colgroupTag))
+ return "table-column-group";
+ else if (element.hasTagName(captionTag))
+ return "table-caption";
+ break;
+ case CSSPropertyWhiteSpace:
+ if (element.hasTagName(preTag))
+ return "pre";
+ inherit = true;
+ break;
+ case CSSPropertyFontStyle:
+ if (element.hasTagName(iTag) || element.hasTagName(citeTag) || element.hasTagName(emTag) || element.hasTagName(varTag) || element.hasTagName(addressTag))
+ return "italic";
+ inherit = true;
+ break;
+ case CSSPropertyFontWeight:
+ if (element.hasTagName(bTag) || element.hasTagName(strongTag) || element.hasTagName(thTag))
+ return "bolder";
+ inherit = true;
+ break;
+ case CSSPropertyTextDecoration:
+ if (element.hasTagName(uTag) || element.hasTagName(insTag))
+ return "underline";
+ else if (element.hasTagName(sTag) || element.hasTagName(strikeTag) || element.hasTagName(delTag))
+ return "line-through";
+ inherit = true; // FIXME: This is not strictly correct
+ break;
+ case CSSPropertyTextAlign:
+ if (element.hasTagName(centerTag) || element.hasTagName(captionTag) || element.hasTagName(thTag))
+ return "center";
+ inherit = true;
+ break;
+ case CSSPropertyVerticalAlign:
+ if (element.hasTagName(supTag))
+ return "super";
+ else if (element.hasTagName(subTag))
+ return "sub";
+ else if (element.hasTagName(theadTag) || element.hasTagName(tbodyTag) || element.hasTagName(tfootTag))
+ return "middle";
+ 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();
+}
+
+- (NSString *)_stringForNode:(DOMNode *)node property:(CSSPropertyID)propertyId
+{
+ Node* coreNode = core(node);
+ if (!coreNode)
+ return nil;
+ String result = _caches->propertyValueForNode(*coreNode, propertyId);
+ if (!result.length())
+ return nil;
+ return result;
+}
+
+static inline bool floatValueFromPrimitiveValue(CSSPrimitiveValue& primitiveValue, float& 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& node, CSSPropertyID propertyId, float& result)
+{
+ if (!node.isElementNode()) {
+ if (ContainerNode* parent = node.parentNode())
+ return floatPropertyValueForNode(*parent, propertyId, result);
+ return false;
+ }
+
+ Element& element = toElement(node);
+ if (RefPtr<CSSValue> value = computedStylePropertyForElement(element, propertyId)) {
+ if (value->isPrimitiveValue() && floatValueFromPrimitiveValue(toCSSPrimitiveValue(*value), result))
+ return true;
+ }
+
+ bool inherit = false;
+ if (RefPtr<CSSValue> value = inlineStylePropertyForElement(element, propertyId)) {
+ if (value->isPrimitiveValue() && floatValueFromPrimitiveValue(toCSSPrimitiveValue(*value), result))
+ return true;
+ if (value->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;
+}
+
+- (BOOL)_getFloat:(CGFloat *)val forNode:(DOMNode *)node property:(CSSPropertyID)propertyId
+{
+ Node* coreNode = core(node);
+ if (!coreNode)
+ return NO;
+ float result;
+ if (!_caches->floatPropertyValueForNode(*coreNode, propertyId, result))
+ return NO;
+ if (val)
+ *val = result;
+ return YES;
+}
+
+static NSString *_NSFirstPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde)
+{
+ NSArray *array = NSSearchPathForDirectoriesInDomains(directory, domainMask, expandTilde);
+ return [array count] >= 1 ? [array objectAtIndex:0] : nil;
+}
+
+static NSString *_NSSystemLibraryPath(void)
+{
+ return _NSFirstPathForDirectoriesInDomains(NSLibraryDirectory, NSSystemDomainMask, YES);
+}
+
+- (NSBundle *)_webKitBundle
+{
+ NSBundle *bundle = [NSBundle bundleWithIdentifier:@"com.apple.WebKit"];
+ if (!bundle)
+ bundle = [NSBundle bundleWithPath:[_NSSystemLibraryPath() stringByAppendingPathComponent:@"Frameworks/WebKit.framework"]];
+ return bundle;
+}
+
+#if PLATFORM(IOS)
+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:@"("];
+ NSRange closeParenRange = [shadowStyle rangeOfString:@")"];
+ NSRange firstRange = NSMakeRange(NSNotFound, 0);
+ NSRange secondRange = NSMakeRange(NSNotFound, 0);
+ NSRange thirdRange = NSMakeRange(NSNotFound, 0);
+ NSRange spaceRange;
+ if (openParenRange.length > 0 && closeParenRange.length > 0 && NSMaxRange(openParenRange) < closeParenRange.location) {
+ NSArray *components = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(openParenRange), closeParenRange.location - NSMaxRange(openParenRange))] componentsSeparatedByString:@","];
+ if ([components count] >= 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] >= 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:@"px"];
+ if (firstRange.length > 0 && NSMaxRange(firstRange) < shadowStyleLength)
+ secondRange = [shadowStyle rangeOfString:@"px" options:0 range:NSMakeRange(NSMaxRange(firstRange), shadowStyleLength - NSMaxRange(firstRange))];
+ if (secondRange.length > 0 && NSMaxRange(secondRange) < shadowStyleLength)
+ thirdRange = [shadowStyle rangeOfString:@"px" options:0 range:NSMakeRange(NSMaxRange(secondRange), shadowStyleLength - NSMaxRange(secondRange))];
+ if (firstRange.location > 0 && firstRange.length > 0 && secondRange.length > 0 && thirdRange.length > 0) {
+ spaceRange = [shadowStyle rangeOfString:@" " 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:@" " 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:@" " 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& element)
+{
+ String displayValue = propertyValueForNode(element, CSSPropertyDisplay);
+ if (displayValue == "block" || displayValue == "list-item" || displayValue.startsWith("table"))
+ return true;
+ String floatValue = propertyValueForNode(element, CSSPropertyFloat);
+ if (floatValue == "left" || floatValue == "right")
+ return true;
+ return false;
+}
+
+bool HTMLConverterCaches::elementHasOwnBackgroundColor(Element& 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("table");
+}
+
+- (BOOL)_elementIsBlockLevel:(DOMElement *)element
+{
+ return element && _caches->isBlockElement(*core(element));
+}
+
+- (BOOL)_elementHasOwnBackgroundColor:(DOMElement *)element
+{
+ return element && _caches->elementHasOwnBackgroundColor(*core(element));
+}
+
+- (DOMElement *)_blockLevelElementForNode:(DOMNode *)node
+{
+ DOMElement *element = (DOMElement *)node;
+ while (element && [element nodeType] != DOM_ELEMENT_NODE)
+ element = (DOMElement *)[element parentNode];
+ if (element && ![self _elementIsBlockLevel:element])
+ element = [self _blockLevelElementForNode:[element 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 < ColorEpsilon && green < ColorEpsilon && blue < ColorEpsilon && (ignoreBlack || alpha < ColorEpsilon))
+ return Color();
+
+ return color;
+}
+
+Color HTMLConverterCaches::colorPropertyValueForNode(Node& node, CSSPropertyID propertyId)
+{
+ if (!node.isElementNode()) {
+ if (Node* parent = node.parentNode())
+ return colorPropertyValueForNode(*parent, propertyId);
+ return Color();
+ }
+
+ Element& element = toElement(node);
+ if (RefPtr<CSSValue> value = computedStylePropertyForElement(element, propertyId)) {
+ if (value->isPrimitiveValue() && toCSSPrimitiveValue(*value).isRGBColor())
+ return normalizedColor(Color(toCSSPrimitiveValue(*value).getRGBA32Value()), propertyId == CSSPropertyColor);
+ }
+
+ bool inherit = false;
+ if (RefPtr<CSSValue> value = inlineStylePropertyForElement(element, propertyId)) {
+ if (value->isPrimitiveValue() && toCSSPrimitiveValue(*value).isRGBColor())
+ return normalizedColor(Color(toCSSPrimitiveValue(*value).getRGBA32Value()), propertyId == CSSPropertyColor);
+ if (value->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 *)_colorForNode:(DOMNode *)node property:(CSSPropertyID)propertyId
+{
+ Node* coreNode = core(node);
+ if (!coreNode)
+ return nil;
+ Color result = _caches->colorPropertyValueForNode(*coreNode, propertyId);
+ if (!result.isValid())
+ return nil;
+ PlatformColor *platformResult = _platformColor(result);
+ if ([[PlatformColorClass clearColor] isEqual:platformResult] || ([platformResult alphaComponent] == 0.0))
+ return nil;
+ return platformResult;
+}
+
+#define UIFloatIsZero(number) (fabs(number - 0) < FLT_EPSILON)
+
+- (NSDictionary *)_computedAttributesForElement:(DOMElement *)element
+{
+ DOMElement *blockElement = [self _blockLevelElementForNode:element];
+ NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
+#if !PLATFORM(IOS)
+ NSFontManager *fontManager = [NSFontManager sharedFontManager];
+#endif
+ NSString *textDecoration = [self _stringForNode:element property:CSSPropertyTextDecoration];
+ NSString *verticalAlign = [self _stringForNode:element property:CSSPropertyVerticalAlign];
+ NSString *textShadow = [self _stringForNode:element property:CSSPropertyTextShadow];
+ NSString *fontLigatures = [self _stringForNode:element property:CSSPropertyWebkitFontVariantLigatures];
+ NSString *fontKerning = [self _stringForNode:element property:CSSPropertyWebkitFontKerning];
+ NSString *letterSpacing = [self _stringForNode:element property:CSSPropertyLetterSpacing];
+ CGFloat fontSize = 0;
+ CGFloat baselineOffset = 0;
+ CGFloat strokeWidth = 0.0;
+ PlatformFont *font = nil;
+ PlatformFont *actualFont = (PlatformFont *)[element _font];
+ PlatformColor *foregroundColor = [self _colorForNode:element property:CSSPropertyColor];
+ PlatformColor *backgroundColor = [self _colorForNode:element property:CSSPropertyBackgroundColor];
+ PlatformColor *strokeColor = [self _colorForNode:element property:CSSPropertyWebkitTextStrokeColor];
+
+ if (![self _getFloat:&fontSize forNode:element property:CSSPropertyFontSize] || fontSize <= 0.0)
+ fontSize = _defaultFontSize;
+ fontSize *= _textSizeMultiplier;
+ if (fontSize < _minimumFontSize) fontSize = _minimumFontSize;
+ if (fabs(floor(2.0 * fontSize + 0.5) / 2.0 - fontSize) < 0.05)
+ fontSize = (CGFloat)floor(2.0 * fontSize + 0.5) / 2;
+ else if (fabs(floor(10.0 * fontSize + 0.5) / 10.0 - fontSize) < 0.005)
+ fontSize = (CGFloat)floor(10.0 * fontSize + 0.5) / 10;
+
+ if (fontSize <= 0.0)
+ fontSize = 12;
+
+#if PLATFORM(IOS)
+ if (actualFont)
+ font = [actualFont fontWithSize:fontSize];
+#else
+ if (actualFont)
+ font = [fontManager convertFont:actualFont toSize:fontSize];
+#endif
+ if (!font) {
+ NSString *fontName = [[self _stringForNode:element property:CSSPropertyFontFamily] capitalizedString];
+ NSString *fontStyle = [self _stringForNode:element property:CSSPropertyFontStyle];
+ NSString *fontWeight = [self _stringForNode:element property:CSSPropertyFontWeight];
+#if !PLATFORM(IOS)
+ NSString *fontVariant = [self _stringForNode:element property:CSSPropertyFontVariant];
+#endif
+ if (!fontName)
+ fontName = _standardFontFamily;
+ if (fontName)
+ font = _fontForNameAndSize(fontName, fontSize, _fontCache);
+ if (!font)
+ font = [PlatformFontClass fontWithName:@"Times" size:fontSize];
+ if ([@"italic" isEqualToString:fontStyle] || [@"oblique" isEqualToString:fontStyle]) {
+ 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;
+ }
+ if ([fontWeight hasPrefix:@"bold"] || [fontWeight integerValue] >= 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 ([@"small-caps" isEqualToString:fontVariant]) {
+ // ??? 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 && ![self _elementHasOwnBackgroundColor:element])
+ [attrs setObject:backgroundColor forKey:NSBackgroundColorAttributeName];
+
+ if ([self _getFloat:&strokeWidth forNode:element property:CSSPropertyWebkitTextStrokeWidth]) {
+ float textStrokeWidth = strokeWidth / ([font pointSize] * 0.01);
+ [attrs setObject:[NSNumber numberWithDouble:textStrokeWidth] forKey:NSStrokeWidthAttributeName];
+ }
+ if(strokeColor)
+ [attrs setObject:strokeColor forKey:NSStrokeColorAttributeName];
+ if (fontKerning || letterSpacing) {
+ if ([fontKerning rangeOfString:@"none"].location != NSNotFound)
+ [attrs setObject:@0.0 forKey:NSKernAttributeName];
+ else {
+ double kernVal = letterSpacing ? [letterSpacing doubleValue] : 0.0;
+ if (UIFloatIsZero(kernVal))
+ [attrs setObject:@0.0 forKey:NSKernAttributeName]; // auto and normal, the other possible values, are both "kerning enabled"
+ else
+ [attrs setObject:[NSNumber numberWithDouble:kernVal] forKey:NSKernAttributeName];
+ }
+ }
+ if (fontLigatures) {
+ if ([fontLigatures rangeOfString:@"normal"].location != NSNotFound)
+ ; // default: whatever the system decides to do
+ else if ([fontLigatures rangeOfString:@"common-ligatures"].location != NSNotFound)
+ [attrs setObject:@1 forKey:NSLigatureAttributeName]; // explicitly enabled
+ else if ([fontLigatures rangeOfString:@"no-common-ligatures"].location != NSNotFound)
+ [attrs setObject:@0 forKey:NSLigatureAttributeName]; // explicitly disabled
+ }
+
+ if (textDecoration && [textDecoration length] > 4) {
+ if ([textDecoration rangeOfString:@"underline"].location != NSNotFound)
+ [attrs setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName];
+ if ([textDecoration rangeOfString:@"line-through"].location != NSNotFound)
+ [attrs setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSStrikethroughStyleAttributeName];
+ }
+ if (verticalAlign) {
+ if ([verticalAlign rangeOfString:@"super"].location != NSNotFound)
+ [attrs setObject:[NSNumber numberWithInteger:1] forKey:NSSuperscriptAttributeName];
+ if ([verticalAlign rangeOfString:@"sub"].location != NSNotFound)
+ [attrs setObject:[NSNumber numberWithInteger:-1] forKey:NSSuperscriptAttributeName];
+ }
+ if ([self _getFloat:&baselineOffset forNode:element property:CSSPropertyVerticalAlign])
+ [attrs setObject:[NSNumber numberWithDouble:baselineOffset] forKey:NSBaselineOffsetAttributeName];
+ if (textShadow && [textShadow length] > 4) {
+ NSShadow *shadow = _shadowForShadowStyle(textShadow);
+ if (shadow)
+ [attrs setObject:shadow forKey:NSShadowAttributeName];
+ }
+ if (element != blockElement && [_writingDirectionArray count] > 0)
+ [attrs setObject:[NSArray arrayWithArray:_writingDirectionArray] forKey:NSWritingDirectionAttributeName];
+
+ if (blockElement) {
+ NSMutableParagraphStyle *paragraphStyle = [[[self class] defaultParagraphStyle] mutableCopy];
+ NSString *blockTag = [blockElement tagName];
+ BOOL isParagraph = ([@"P" isEqualToString:blockTag] || [@"LI" isEqualToString:blockTag] || ([blockTag hasPrefix:@"H"] && 2 == [blockTag length]));
+ NSString *textAlign = [self _stringForNode:blockElement property:CSSPropertyTextAlign];
+ NSString *direction = [self _stringForNode:blockElement property:CSSPropertyDirection];
+ NSString *hyphenation = [self _stringForNode:blockElement property:CSSPropertyWebkitHyphens];
+ CGFloat leftMargin = 0;
+ CGFloat rightMargin = 0;
+ CGFloat bottomMargin = 0;
+ CGFloat textIndent = 0;
+ CGFloat lineHeight = 0;
+ if (textAlign) {
+ // WebKit can return -khtml-left, -khtml-right, -khtml-center
+ if ([textAlign hasSuffix:@"left"])
+ [paragraphStyle setAlignment:NSTextAlignmentLeft];
+ else if ([textAlign hasSuffix:@"right"])
+ [paragraphStyle setAlignment:NSTextAlignmentRight];
+ else if ([textAlign hasSuffix:@"center"])
+ [paragraphStyle setAlignment:NSTextAlignmentCenter];
+ else if ([textAlign hasSuffix:@"justify"])
+ [paragraphStyle setAlignment:NSTextAlignmentJustified];
+ }
+ if (direction) {
+ if ([direction isEqualToString:@"ltr"])
+ [paragraphStyle setBaseWritingDirection:NSWritingDirectionLeftToRight];
+ else if ([direction isEqualToString:@"rtl"])
+ [paragraphStyle setBaseWritingDirection:NSWritingDirectionRightToLeft];
+ }
+ if(hyphenation) {
+ if ([hyphenation isEqualToString:@"auto"])
+ [paragraphStyle setHyphenationFactor:1.0];
+ else
+ [paragraphStyle setHyphenationFactor:0.0];
+ }
+ if ([blockTag hasPrefix:@"H"] && 2 == [blockTag length]) {
+ NSInteger headerLevel = [blockTag characterAtIndex:1] - '0';
+ if (1 <= headerLevel && headerLevel <= 6)
+ [paragraphStyle setHeaderLevel:headerLevel];
+ }
+ if (isParagraph) {
+ if ([self _getFloat:&leftMargin forNode:blockElement property:CSSPropertyMarginLeft] && leftMargin > 0.0)
+ [paragraphStyle setHeadIndent:leftMargin];
+ if ([self _getFloat:&textIndent forNode:blockElement property:CSSPropertyTextIndent])
+ [paragraphStyle setFirstLineHeadIndent:[paragraphStyle headIndent] + textIndent];
+ if ([self _getFloat:&rightMargin forNode:blockElement property:CSSPropertyMarginRight] && rightMargin > 0.0)
+ [paragraphStyle setTailIndent:-rightMargin];
+ if ([self _getFloat:&bottomMargin forNode:blockElement property:CSSPropertyMarginBottom] && bottomMargin > 0.0)
+ [paragraphStyle setParagraphSpacing:bottomMargin];
+ }
+ if (_webViewTextSizeMultiplier > 0.0 && [self _getFloat:&lineHeight forNode:element property:CSSPropertyLineHeight] && lineHeight > 0.0)
+ [paragraphStyle setMinimumLineHeight:lineHeight / _webViewTextSizeMultiplier];
+ if ([_textLists count] > 0)
+ [paragraphStyle setTextLists:_textLists];
+ if ([_textBlocks count] > 0)
+ [paragraphStyle setTextBlocks:_textBlocks];
+ [attrs setObject:paragraphStyle forKey:NSParagraphStyleAttributeName];
+ [paragraphStyle release];
+ }
+ return attrs;
+}
+
+- (NSDictionary *)_attributesForElement:(DOMElement *)element
+{
+ NSDictionary *result;
+ if (element) {
+ result = [_attributesForElements objectForKey:element];
+ if (!result) {
+ result = [self _computedAttributesForElement:element];
+ [_attributesForElements setObject:result forKey:element];
+ }
+ } else
+ result = [NSDictionary dictionary];
+ return result;
+
+}
+
+- (void)_newParagraphForElement:(DOMElement *)element tag:(NSString *)tag allowEmpty:(BOOL)flag suppressTrailingSpace:(BOOL)suppress
+{
+ NSUInteger textLength = [_attrStr length];
+ unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n';
+ NSRange rangeToReplace = (suppress && _flags.isSoft && (lastChar == ' ' || lastChar == NSLineSeparatorCharacter)) ? NSMakeRange(textLength - 1, 1) : NSMakeRange(textLength, 0);
+ BOOL needBreak = (flag || lastChar != '\n');
+ if (needBreak) {
+ NSString *string = (([@"BODY" isEqualToString:tag] || [@"HTML" isEqualToString:tag]) ? @"" : @"\n");
+ [_writingDirectionArray removeAllObjects];
+ [_attrStr replaceCharactersInRange:rangeToReplace withString:string];
+ if (rangeToReplace.location < _domRangeStartIndex)
+ _domRangeStartIndex += [string length] - rangeToReplace.length;
+ rangeToReplace.length = [string length];
+ if (!_flags.isIndexing) {
+ NSDictionary *attrs = [self _attributesForElement:element];
+ if (!_flags.isTesting && rangeToReplace.length > 0)
+ [_attrStr setAttributes:attrs range:rangeToReplace];
+ }
+ _flags.isSoft = YES;
+ }
+}
+
+- (void)_newLineForElement:(DOMElement *)element
+{
+ unichar c = NSLineSeparatorCharacter;
+ RetainPtr<NSString> string = adoptNS([[NSString alloc] initWithCharacters:&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 < _domRangeStartIndex) _domRangeStartIndex += rangeToReplace.length;
+ if (!_flags.isIndexing) {
+ NSDictionary *attrs = [self _attributesForElement:element];
+ if (!_flags.isTesting && rangeToReplace.length > 0)
+ [_attrStr setAttributes:attrs range:rangeToReplace];
+ }
+ _flags.isSoft = YES;
+}
+
+- (void)_newTabForElement:(DOMElement *)element
+{
+ NSString *string = @"\t";
+ NSUInteger textLength = [_attrStr length];
+ unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n';
+ NSRange rangeToReplace = (_flags.isSoft && lastChar == ' ') ? NSMakeRange(textLength - 1, 1) : NSMakeRange(textLength, 0);
+ [_attrStr replaceCharactersInRange:rangeToReplace withString:string];
+ rangeToReplace.length = [string length];
+ if (rangeToReplace.location < _domRangeStartIndex)
+ _domRangeStartIndex += rangeToReplace.length;
+ if (!_flags.isIndexing) {
+ NSDictionary *attrs = [self _attributesForElement:element];
+ if (!_flags.isTesting && rangeToReplace.length > 0)
+ [_attrStr setAttributes:attrs range:rangeToReplace];
+ }
+ _flags.isSoft = YES;
+}
+
+- (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("MFWebMessageDocument");
+ if (_WebMessageDocumentClass && ![_WebMessageDocumentClass respondsToSelector:@selector(document:attachment:forURL:)])
+ _WebMessageDocumentClass = Nil;
+ lookedUpClass = YES;
+ }
+ return _WebMessageDocumentClass;
+}
+
+- (BOOL)_addAttachmentForElement:(DOMElement *)element URL:(NSURL *)url needsParagraph:(BOOL)needsParagraph usePlaceholder:(BOOL)flag
+{
+ BOOL retval = NO, notFound = NO;
+ NSFileWrapper *fileWrapper = nil;
+ Frame* frame = core([element ownerDocument])->frame();
+ DocumentLoader *dataSource = frame->loader().frameHasLoaded() ? frame->loader().documentLoader() : 0;
+ BOOL ignoreOrientation = YES;
+
+ if (_flags.isIndexing)
+ return NO;
+ if ([url isFileURL]) {
+ NSString *path = [[url path] stringByStandardizingPath];
+ if (path)
+ fileWrapper = [[[NSFileWrapper alloc] initWithURL:url options:0 error:NULL] autorelease];
+ }
+ if (!fileWrapper) {
+ RefPtr<ArchiveResource> resource = dataSource->subresource(url);
+ if (!resource)
+ resource = dataSource->subresource(url);
+
+ const String& mimeType = resource->mimeType();
+ if (flag && resource && mimeType == "text/html")
+ notFound = YES;
+ if (resource && !notFound) {
+ fileWrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:resource->data()->createNSData().get()] autorelease];
+ [fileWrapper setPreferredFilename:suggestedFilenameWithMIMEType(url, mimeType)];
+ }
+ }
+#if !PLATFORM(IOS)
+ if (!fileWrapper && !notFound) {
+ fileWrapper = fileWrapperForURL(dataSource, url);
+ if (flag && fileWrapper && [[[[fileWrapper preferredFilename] pathExtension] lowercaseString] hasPrefix:@"htm"]) notFound = YES;
+ if (notFound) fileWrapper = nil;
+ }
+ if (!fileWrapper && !notFound) {
+ fileWrapper = fileWrapperForURL(_dataSource, url);
+ if (flag && fileWrapper && [[[[fileWrapper preferredFilename] pathExtension] lowercaseString] hasPrefix:@"htm"]) notFound = YES;
+ if (notFound) fileWrapper = nil;
+ }
+#endif
+ if (!fileWrapper && !notFound && url) {
+ // Special handling for Mail attachments, until WebKit provides a standard way to get the data.
+ Class WebMessageDocumentClass = [self _WebMessageDocumentClass];
+ if (WebMessageDocumentClass) {
+ NSTextAttachment *mimeTextAttachment = nil;
+ [WebMessageDocumentClass document:NULL attachment:&mimeTextAttachment forURL:url];
+ if (mimeTextAttachment && [mimeTextAttachment respondsToSelector:@selector(fileWrapper)]) {
+ fileWrapper = [mimeTextAttachment performSelector:@selector(fileWrapper)];
+ ignoreOrientation = NO;
+ }
+ }
+ }
+ if (fileWrapper || flag) {
+ NSUInteger textLength = [_attrStr length];
+ RetainPtr<NSTextAttachment> attachment = adoptNS([[PlatformNSTextAttachment alloc] initWithFileWrapper:fileWrapper]);
+#if PLATFORM(IOS)
+ NSString *vAlign = [self _stringForNode:element property:CSSPropertyVerticalAlign];
+ attachment.get().bounds = CGRectMake(0, ([vAlign floatValue] / 100.) * element.clientHeight, element.clientWidth, element.clientHeight);
+#endif
+ RetainPtr<NSString> string = adoptNS([[NSString alloc] initWithFormat:(needsParagraph ? @"%C\n" : @"%C"), static_cast<unichar>(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 = [[self _webKitBundle] URLForResource:@"missing_image" withExtension:@"tiff"];
+ ASSERT_WITH_MESSAGE(missingImageURL != nil, "Unable to find missing_image.tiff!");
+ 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 < _domRangeStartIndex)
+ _domRangeStartIndex += rangeToReplace.length;
+ attrs = [self _attributesForElement:element];
+ if (!_flags.isTesting && rangeToReplace.length > 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)_addQuoteForElement:(DOMElement *)element opening:(BOOL)opening level:(NSInteger)level
+{
+ unichar c = ((level % 2) == 0) ? (opening ? 0x201c : 0x201d) : (opening ? 0x2018 : 0x2019);
+ RetainPtr<NSString> string = adoptNS([[NSString alloc] initWithCharacters:&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 < _domRangeStartIndex)
+ _domRangeStartIndex += rangeToReplace.length;
+ if (!_flags.isIndexing) {
+ RetainPtr<NSDictionary> attrs = [self _attributesForElement:element];
+ if (!_flags.isTesting && rangeToReplace.length > 0)
+ [_attrStr setAttributes:attrs.get() range:rangeToReplace];
+ }
+ _flags.isSoft = NO;
+}
+
+- (void)_addValue:(NSString *)value forElement:(DOMElement *)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 < _domRangeStartIndex)
+ _domRangeStartIndex += rangeToReplace.length;
+ if (!_flags.isIndexing) {
+ RetainPtr<NSDictionary> attrs = [self _attributesForElement:element];
+ if (!_flags.isTesting && rangeToReplace.length > 0)
+ [_attrStr setAttributes:attrs.get() range:rangeToReplace];
+ }
+ _flags.isSoft = NO;
+ }
+}
+
+- (void)_fillInBlock:(NSTextBlock *)block forElement:(DOMElement *)element backgroundColor:(PlatformColor *)backgroundColor extraMargin:(CGFloat)extraMargin extraPadding:(CGFloat)extraPadding isTable:(BOOL)isTable
+{
+ CGFloat val = 0;
+ PlatformColor *color = nil;
+ BOOL isTableCellElement = [element isKindOfClass:[DOMHTMLTableCellElement class]];
+ NSString *width = isTableCellElement ? [(DOMHTMLTableCellElement *)element width] : [element getAttribute:@"width"];
+
+ if ((width && [width length]) || !isTable) {
+ if ([self _getFloat:&val forNode:element property:CSSPropertyWidth])
+ [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockWidth];
+ }
+
+ if ([self _getFloat:&val forNode:element property:CSSPropertyMinWidth])
+ [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMinimumWidth];
+ if ([self _getFloat:&val forNode:element property:CSSPropertyMaxWidth])
+ [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMaximumWidth];
+ if ([self _getFloat:&val forNode:element property:CSSPropertyMinHeight])
+ [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMinimumHeight];
+ if ([self _getFloat:&val forNode:element property:CSSPropertyMaxHeight])
+ [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMaximumHeight];
+
+ if ([self _getFloat:&val forNode:element property:CSSPropertyPaddingLeft])
+ [block setWidth:val + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinXEdge];
+ else [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinXEdge];
+ if ([self _getFloat:&val forNode:element property:CSSPropertyPaddingTop])
+ [block setWidth:val + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinYEdge]; else [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinYEdge];
+ if ([self _getFloat:&val forNode:element property:CSSPropertyPaddingRight])
+ [block setWidth:val + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxXEdge]; else [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxXEdge];
+ if ([self _getFloat:&val forNode:element property:CSSPropertyPaddingBottom])
+ [block setWidth:val + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxYEdge]; else [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxYEdge];
+
+ if ([self _getFloat:&val forNode:element property:CSSPropertyBorderLeftWidth])
+ [block setWidth:val type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMinXEdge];
+ if ([self _getFloat:&val forNode:element property:CSSPropertyBorderTopWidth])
+ [block setWidth:val type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMinYEdge];
+ if ([self _getFloat:&val forNode:element property:CSSPropertyBorderRightWidth])
+ [block setWidth:val type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMaxXEdge];
+ if ([self _getFloat:&val forNode:element property:CSSPropertyBorderBottomWidth])
+ [block setWidth:val type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMaxYEdge];
+
+ if ([self _getFloat:&val forNode:element property:CSSPropertyMarginLeft])
+ [block setWidth:val + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinXEdge]; else [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinXEdge];
+ if ([self _getFloat:&val forNode:element property:CSSPropertyMarginTop])
+ [block setWidth:val + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinYEdge]; else [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinYEdge];
+ if ([self _getFloat:&val forNode:element property:CSSPropertyMarginRight])
+ [block setWidth:val + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxXEdge]; else [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxXEdge];
+ if ([self _getFloat:&val forNode:element property:CSSPropertyMarginBottom])
+ [block setWidth:val + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxYEdge]; else [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxYEdge];
+
+ if ((color = [self _colorForNode:element property:CSSPropertyBackgroundColor]))
+ [block setBackgroundColor:color];
+ if (!color && backgroundColor) [block setBackgroundColor:backgroundColor];
+ if ((color = [self _colorForNode:element property:CSSPropertyBorderLeftColor]))
+ [block setBorderColor:color forEdge:NSMinXEdge];
+ if ((color = [self _colorForNode:element property:CSSPropertyBorderTopColor]))
+ [block setBorderColor:color forEdge:NSMinYEdge];
+ if ((color = [self _colorForNode:element property:CSSPropertyBorderRightColor]))
+ [block setBorderColor:color forEdge:NSMaxXEdge];
+ if ((color = [self _colorForNode:element property: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<NSDateComponents> dateComponents = adoptNS([[NSDateComponents alloc] init]);
+
+ // Set the time zone to GMT
+ [dateComponents setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
+
+ NSInteger year = 0;
+ while (*p && isASCIIDigit(*p))
+ year = 10 * year + *p++ - '0';
+ if (*p++ != '-')
+ return nil;
+ [dateComponents setYear:year];
+
+ int8_t component;
+ if (!read2DigitNumber(&p, &component) || *p++ != '-')
+ return nil;
+ [dateComponents setMonth:component];
+
+ if (!read2DigitNumber(&p, &component) || *p++ != 'T')
+ return nil;
+ [dateComponents setDay:component];
+
+ if (!read2DigitNumber(&p, &component) || *p++ != ':')
+ return nil;
+ [dateComponents setHour:component];
+
+ if (!read2DigitNumber(&p, &component) || *p++ != ':')
+ return nil;
+ [dateComponents setMinute:component];
+
+ if (!read2DigitNumber(&p, &component) || *p++ != 'Z')
+ return nil;
+ [dateComponents setSecond:component];
+
+#if (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 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 < col2) ? NSOrderedAscending : ((col1 == col2) ? NSOrderedSame : NSOrderedDescending));
+}
+
+- (void)_processMetaElementWithName:(NSString *)name content:(NSString *)content {
+ NSString *key = nil;
+ if (NSOrderedSame == [@"CocoaVersion" compare:name options:NSCaseInsensitiveSearch]) {
+ CGFloat versionNumber = [content doubleValue];
+ if (versionNumber > 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 == [@"Generator" compare:name options:NSCaseInsensitiveSearch]) {
+ key = NSGeneratorDocumentAttribute;
+#endif
+ } else if (NSOrderedSame == [@"Keywords" compare:name options:NSCaseInsensitiveSearch]) {
+ if (content && [content length] > 0) {
+ NSArray *array;
+ // ??? need better handling here and throughout
+ if ([content rangeOfString:@", "].length == 0 && [content rangeOfString:@","].length > 0)
+ array = [content componentsSeparatedByString:@","];
+ else if ([content rangeOfString:@", "].length == 0 && [content rangeOfString:@" "].length > 0)
+ array = [content componentsSeparatedByString:@" "];
+ else
+ array = [content componentsSeparatedByString:@", "];
+ [_documentAttrs setObject:array forKey:NSKeywordsDocumentAttribute];
+ }
+ } else if (NSOrderedSame == [@"Author" compare:name options:NSCaseInsensitiveSearch])
+ key = NSAuthorDocumentAttribute;
+ else if (NSOrderedSame == [@"LastAuthor" compare:name options:NSCaseInsensitiveSearch])
+ key = NSEditorDocumentAttribute;
+ else if (NSOrderedSame == [@"Company" compare:name options:NSCaseInsensitiveSearch])
+ key = NSCompanyDocumentAttribute;
+ else if (NSOrderedSame == [@"Copyright" compare:name options:NSCaseInsensitiveSearch])
+ key = NSCopyrightDocumentAttribute;
+ else if (NSOrderedSame == [@"Subject" compare:name options:NSCaseInsensitiveSearch])
+ key = NSSubjectDocumentAttribute;
+ else if (NSOrderedSame == [@"Description" compare:name options:NSCaseInsensitiveSearch] || NSOrderedSame == [@"Comment" compare:name options:NSCaseInsensitiveSearch])
+ key = NSCommentDocumentAttribute;
+ else if (NSOrderedSame == [@"CreationTime" compare:name options:NSCaseInsensitiveSearch]) {
+ if (content && [content length] > 0) {
+ NSDate *date = _dateForString(content);
+ if (date)
+ [_documentAttrs setObject:date forKey:NSCreationTimeDocumentAttribute];
+ }
+ } else if (NSOrderedSame == [@"ModificationTime" compare:name options:NSCaseInsensitiveSearch]) {
+ if (content && [content length] > 0) {
+ NSDate *date = _dateForString(content);
+ if (date)
+ [_documentAttrs setObject:date forKey:NSModificationTimeDocumentAttribute];
+ }
+ }
+#if PLATFORM(IOS)
+ else if (NSOrderedSame == [@"DisplayName" compare:name options:NSCaseInsensitiveSearch] || NSOrderedSame == [@"IndexTitle" compare:name options:NSCaseInsensitiveSearch])
+ key = NSDisplayNameDocumentAttribute;
+ else if (NSOrderedSame == [@"robots" compare:name options:NSCaseInsensitiveSearch]) {
+ if ([content rangeOfString:@"noindex" options:NSCaseInsensitiveSearch].length > 0)
+ [_documentAttrs setObject:[NSNumber numberWithInteger:1] forKey:NSNoIndexDocumentAttribute];
+ }
+#endif
+ if (key && content && [content length] > 0)
+ [_documentAttrs setObject:content forKey:key];
+}
+
+- (void)_processHeadElement:(DOMElement *)element {
+ // ??? should gather data from other sources e.g. Word, but for that we would need to be able to get comments from DOM
+ NSArray *childNodes = [self _childrenForNode:element];
+ NSUInteger count = [childNodes count];
+ for (NSUInteger i = 0; i < count; i++) {
+ DOMNode *node = [childNodes objectAtIndex:i];
+ unsigned short nodeType = [node nodeType];
+ if (DOM_ELEMENT_NODE == nodeType) {
+ DOMElement *element = (DOMElement *)node;
+ NSString *tag = [element tagName];
+ if ([@"META" isEqualToString:tag] && [element respondsToSelector:@selector(name)] && [element respondsToSelector:@selector(content)]) {
+ NSString *name = [(DOMHTMLMetaElement *)element name];
+ NSString *content = [(DOMHTMLMetaElement *)element content];
+ if (name && content)
+ [self _processMetaElementWithName:name content:content];
+ }
+ }
+ }
+}
+
+- (BOOL)_enterElement:(DOMElement *)element tag:(NSString *)tag display:(NSString *)displayVal embedded:(BOOL)embedded
+{
+ if ([@"HEAD" isEqualToString:tag] && !embedded)
+ [self _processHeadElement:element];
+ else if (!displayVal || !([@"none" isEqualToString:displayVal] || [@"table-column" isEqualToString:displayVal] || [@"table-column-group" isEqualToString:displayVal])) {
+ if ([self _elementIsBlockLevel:element] && ![@"BR" isEqualToString:tag] && !([@"table-cell" isEqualToString:displayVal] && [_textTables count] == 0)
+ && !([_textLists count] > 0 && [@"block" isEqualToString:displayVal] && ![@"LI" isEqualToString:tag] && ![@"UL" isEqualToString:tag] && ![@"OL" isEqualToString:tag]))
+ [self _newParagraphForElement:element tag:tag allowEmpty:NO suppressTrailingSpace:YES];
+ return YES;
+ }
+ return NO;
+}
+
+- (void)_addTableForElement:(DOMElement *)tableElement
+{
+ RetainPtr<NSTextTable> 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) {
+ NSString *borderCollapse = [self _stringForNode:tableElement property:CSSPropertyBorderCollapse];
+ NSString *emptyCells = [self _stringForNode:tableElement property:CSSPropertyEmptyCells];
+ NSString *tableLayout = [self _stringForNode:tableElement property:CSSPropertyTableLayout];
+ if ([tableElement respondsToSelector:@selector(cellSpacing)]) {
+ NSString *cellSpacing = [(DOMHTMLTableElement *)tableElement cellSpacing];
+ if (cellSpacing && [cellSpacing length] > 0 && ![cellSpacing hasSuffix:@"%"]) cellSpacingVal = [cellSpacing floatValue];
+ }
+ if ([tableElement respondsToSelector:@selector(cellPadding)]) {
+ NSString *cellPadding = [(DOMHTMLTableElement *)tableElement cellPadding];
+ if (cellPadding && [cellPadding length] > 0 && ![cellPadding hasSuffix:@"%"]) cellPaddingVal = [cellPadding floatValue];
+ }
+ [self _fillInBlock:table.get() forElement:tableElement backgroundColor:nil extraMargin:0 extraPadding:0 isTable:YES];
+ if ([@"collapse" isEqualToString:borderCollapse]) {
+ [table setCollapsesBorders:YES];
+ cellSpacingVal = 0;
+ }
+ if ([@"hide" isEqualToString:emptyCells]) [table setHidesEmptyCells:YES];
+ if ([@"fixed" isEqualToString:tableLayout]) [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)_addTableCellForElement:(DOMElement *)tableCellElement
+{
+ 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] > 0) ? [_textTableRowBackgroundColors lastObject] : nil;
+ NSTextTableBlock *previousBlock;
+ CGFloat cellSpacingVal = [[_textTableSpacings lastObject] floatValue];
+ if ([color isEqual:[PlatformColorClass clearColor]]) color = nil;
+ for (NSUInteger i = 0; i < count; i++) {
+ previousBlock = [rowArray objectAtIndex:i];
+ if (columnNumber >= [previousBlock startingColumn] && columnNumber < [previousBlock startingColumn] + [previousBlock columnSpan])
+ columnNumber = [previousBlock startingColumn] + [previousBlock columnSpan];
+ }
+ if (tableCellElement) {
+ if ([tableCellElement respondsToSelector:@selector(rowSpan)]) {
+ rowSpan = [(DOMHTMLTableCellElement *)tableCellElement rowSpan];
+ if (rowSpan < 1)
+ rowSpan = 1;
+ }
+ if ([tableCellElement respondsToSelector:@selector(colSpan)]) {
+ colSpan = [(DOMHTMLTableCellElement *)tableCellElement colSpan];
+ if (colSpan < 1)
+ colSpan = 1;
+ }
+ }
+ RetainPtr<NSTextTableBlock> block = adoptNS([[PlatformNSTextTableBlock alloc] initWithTable:table startingRow:rowNumber rowSpan:rowSpan startingColumn:columnNumber columnSpan:colSpan]);
+ if (tableCellElement) {
+ NSString *verticalAlign = [self _stringForNode:tableCellElement property:CSSPropertyVerticalAlign];
+ [self _fillInBlock:block.get() forElement:tableCellElement backgroundColor:color extraMargin:cellSpacingVal / 2 extraPadding:0 isTable:NO];
+ if ([@"middle" isEqualToString:verticalAlign])
+ [block setVerticalAlignment:NSTextBlockMiddleAlignment];
+ else if ([@"bottom" isEqualToString:verticalAlign])
+ [block setVerticalAlignment:NSTextBlockBottomAlignment];
+ else if ([@"baseline" isEqualToString:verticalAlign])
+ [block setVerticalAlignment:NSTextBlockBaselineAlignment];
+ else if ([@"top" isEqualToString:verticalAlign])
+ [block setVerticalAlignment:NSTextBlockTopAlignment];
+ }
+ [_textBlocks addObject:block.get()];
+ [rowArray addObject:block.get()];
+ [rowArray sortUsingFunction:_colCompare context:NULL];
+}
+
+- (BOOL)_processElement:(DOMElement *)element tag:(NSString *)tag display:(NSString *)displayVal depth:(NSInteger)depth
+{
+ BOOL retval = YES;
+ BOOL isBlockLevel = [self _elementIsBlockLevel:element];
+ if (isBlockLevel)
+ [_writingDirectionArray removeAllObjects];
+ else {
+ NSString *bidi = [self _stringForNode:element property:CSSPropertyUnicodeBidi];
+ if (bidi && [bidi isEqualToString:@"embed"]) {
+ NSUInteger val = NSTextWritingDirectionEmbedding;
+ NSString *direction = [self _stringForNode:element property:CSSPropertyDirection];
+ if ([direction isEqualToString:@"rtl"])
+ val |= NSWritingDirectionRightToLeft;
+ [_writingDirectionArray addObject:[NSNumber numberWithUnsignedInteger:val]];
+ } else if (bidi && [bidi isEqualToString:@"bidi-override"]) {
+ NSUInteger val = NSTextWritingDirectionOverride;
+ NSString *direction = [self _stringForNode:element property:CSSPropertyDirection];
+ if ([direction isEqualToString:@"rtl"])
+ val |= NSWritingDirectionRightToLeft;
+ [_writingDirectionArray addObject:[NSNumber numberWithUnsignedInteger:val]];
+ }
+ }
+ if ([@"table" isEqualToString:displayVal] || ([_textTables count] == 0 && [@"table-row-group" isEqualToString:displayVal])) {
+ DOMElement *tableElement = element;
+ if ([@"table-row-group" isEqualToString:displayVal]) {
+ // If we are starting in medias res, the first thing we see may be the tbody, so go up to the table
+ tableElement = [self _blockLevelElementForNode:[element parentNode]];
+ if (![@"table" isEqualToString:[self _stringForNode:tableElement property:CSSPropertyDisplay]])
+ tableElement = element;
+ }
+ while ([_textTables count] > [_textBlocks count])
+ [self _addTableCellForElement:nil];
+ [self _addTableForElement:tableElement];
+ } else if ([@"table-footer-group" isEqualToString:displayVal] && [_textTables count] > 0) {
+ [_textTableFooters setObject:element forKey:[NSValue valueWithNonretainedObject:[_textTables lastObject]]];
+ retval = NO;
+ } else if ([@"table-row" isEqualToString:displayVal] && [_textTables count] > 0) {
+ PlatformColor *color = [self _colorForNode:element property:CSSPropertyBackgroundColor];
+ if (!color) color = [PlatformColorClass clearColor];
+ [_textTableRowBackgroundColors addObject:color];
+ } else if ([@"table-cell" isEqualToString:displayVal]) {
+ while ([_textTables count] < [_textBlocks count] + 1) {
+ [self _addTableForElement:nil];
+ }
+ [self _addTableCellForElement:element];
+ } else if ([@"IMG" isEqualToString:tag]) {
+ NSString *urlString = [element getAttribute:@"src"];
+ if (urlString && [urlString length] > 0) {
+ NSURL *url = core([element ownerDocument])->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)
+ [self _addAttachmentForElement:element URL:url needsParagraph:isBlockLevel usePlaceholder:usePlaceholderImage];
+ }
+ retval = NO;
+ } else if ([@"OBJECT" isEqualToString:tag]) {
+ NSString *baseString = [element getAttribute:@"codebase"];
+ NSString *urlString = [element getAttribute:@"data"];
+ NSString *declareString = [element getAttribute:@"declare"];
+ if (urlString && [urlString length] > 0 && ![@"true" isEqualToString:declareString]) {
+ NSURL *baseURL = nil;
+ NSURL *url = nil;
+ if (baseString && [baseString length] > 0) {
+ baseURL = core([element ownerDocument])->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 =core([element ownerDocument])->completeURL(stripLeadingAndTrailingHTMLSpaces(urlString));
+ if (!url)
+ url = [NSURL _web_URLWithString:[urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] relativeToURL:_baseURL];
+ if (url)
+ retval = ![self _addAttachmentForElement:element URL:url needsParagraph:isBlockLevel usePlaceholder:NO];
+ }
+ } else if ([@"FRAME" isEqualToString:tag]) {
+ if ([element respondsToSelector:@selector(contentDocument)]) {
+ DOMDocument *contentDocument = [(DOMHTMLFrameElement *)element contentDocument];
+ if (contentDocument)
+ [self _traverseNode:contentDocument depth:depth + 1 embedded:YES];
+ }
+ retval = NO;
+ } else if ([@"IFRAME" isEqualToString:tag]) {
+ if ([element respondsToSelector:@selector(contentDocument)]) {
+ DOMDocument *contentDocument = [(DOMHTMLIFrameElement *)element contentDocument];
+ if (contentDocument) {
+ [self _traverseNode:contentDocument depth:depth + 1 embedded:YES];
+ retval = NO;
+ }
+ }
+ } else if ([@"BR" isEqualToString:tag]) {
+ DOMElement *blockElement = [self _blockLevelElementForNode:[element parentNode]];
+ NSString *breakClass = [element getAttribute:@"class"], *blockTag = [blockElement tagName];
+ BOOL isExtraBreak = [@"Apple-interchange-newline" isEqualToString:breakClass], blockElementIsParagraph = ([@"P" isEqualToString:blockTag] || [@"LI" isEqualToString:blockTag] || ([blockTag hasPrefix:@"H"] && 2 == [blockTag length]));
+ if (isExtraBreak)
+ _flags.hasTrailingNewline = YES;
+ else {
+ if (blockElement && blockElementIsParagraph)
+ [self _newLineForElement:element];
+ else
+ [self _newParagraphForElement:element tag:tag allowEmpty:YES suppressTrailingSpace:NO];
+ }
+ } else if ([@"UL" isEqualToString:tag]) {
+ RetainPtr<NSTextList> list;
+ NSString *listStyleType = [self _stringForNode:element property:CSSPropertyListStyleType];
+ if (!listStyleType || [listStyleType length] == 0)
+ listStyleType = @"disc";
+ list = adoptNS([[PlatformNSTextList alloc] initWithMarkerFormat:[NSString stringWithFormat:@"{%@}", listStyleType] options:0]);
+ [_textLists addObject:list.get()];
+ } else if ([@"OL" isEqualToString:tag]) {
+ RetainPtr<NSTextList> list;
+ NSString *listStyleType = [self _stringForNode:element property:CSSPropertyListStyleType];
+ if (!listStyleType || [listStyleType length] == 0) listStyleType = @"decimal";
+ list = adoptNS([[PlatformNSTextList alloc] initWithMarkerFormat:[NSString stringWithFormat:@"{%@}.", listStyleType] options:0]);
+ if ([element respondsToSelector:@selector(start)]) {
+ NSInteger startingItemNumber = [(DOMHTMLOListElement *)element start];
+ [list setStartingItemNumber:startingItemNumber];
+ }
+ [_textLists addObject:list.get()];
+ } else if ([@"Q" isEqualToString:tag]) {
+ [self _addQuoteForElement:element opening:YES level:_quoteLevel++];
+ } else if ([@"INPUT" isEqualToString:tag]) {
+ if ([element respondsToSelector:@selector(type)] && [element respondsToSelector:@selector(value)] && [@"text" compare:[(DOMHTMLInputElement *)element type] options:NSCaseInsensitiveSearch] == NSOrderedSame) {
+ NSString *value = [(DOMHTMLInputElement *)element value];
+ if (value && [value length] > 0) [self _addValue:value forElement:element];
+ }
+ } else if ([@"TEXTAREA" isEqualToString:tag]) {
+ if ([element respondsToSelector:@selector(value)]) {
+ NSString *value = [(DOMHTMLTextAreaElement *)element value];
+ if (value && [value length] > 0) [self _addValue:value forElement:element];
+ }
+ retval = NO;
+ }
+ return retval;
+}
+
+- (void)_addMarkersToList:(NSTextList *)list range:(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 >= textLength)
+ return;
+ if (NSMaxRange(range) > 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 && listIndex != NSNotFound) {
+ for (NSUInteger idx = range.location; idx < NSMaxRange(range);) {
+ paragraphRange = [string paragraphRangeForRange:NSMakeRange(idx, 0)];
+ paragraphStyle = [_attrStr attribute:NSParagraphStyleAttributeName atIndex:idx effectiveRange:&styleRange];
+ font = [_attrStr attribute:NSFontAttributeName atIndex:idx effectiveRange:NULL];
+ pointSize = font ? [font pointSize] : 12;
+ if ([[paragraphStyle textLists] count] == listIndex + 1) {
+ stringToInsert = [NSString stringWithFormat:@"\t%@\t", [list markerForItemNumber:itemNum++]];
+ insertLength = [stringToInsert length];
+ if (!_flags.isIndexing && !_flags.isTesting)
+ attrsToInsert = [PlatformNSTextList _standardMarkerAttributesForAttributes:[_attrStr attributesAtIndex:paragraphRange.location effectiveRange:NULL]];
+
+ [_attrStr replaceCharactersInRange:NSMakeRange(paragraphRange.location, 0) withString:stringToInsert];
+ if (!_flags.isIndexing && !_flags.isTesting) [_attrStr setAttributes:attrsToInsert range:NSMakeRange(paragraphRange.location, insertLength)];
+ range.length += insertLength;
+ paragraphRange.length += insertLength;
+ if (paragraphRange.location < _domRangeStartIndex) _domRangeStartIndex += insertLength;
+
+ newStyle = [paragraphStyle mutableCopy];
+ listLocation = (listIndex + 1) * 36;
+ markerLocation = listLocation - 25;
+ [newStyle setFirstLineHeadIndent:0];
+ [newStyle setHeadIndent:listLocation];
+ while ((count = [[newStyle tabStops] count]) > 0) {
+ for (i = 0, tabToRemove = nil; !tabToRemove && i < count; i++) {
+ tab = [[newStyle tabStops] objectAtIndex:i];
+ if ([tab location] <= 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];
+ if (!_flags.isIndexing && !_flags.isTesting) [_attrStr addAttribute:NSParagraphStyleAttributeName value:newStyle range:paragraphRange];
+ [newStyle release];
+
+ idx = NSMaxRange(paragraphRange);
+ } else {
+ // skip any deeper-nested lists
+ idx = NSMaxRange(styleRange);
+ }
+ }
+ }
+ }
+}
+
+- (void)_exitElement:(DOMElement *)element tag:(NSString *)tag display:(NSString *)displayVal depth:(NSInteger)depth startIndex:(NSUInteger)startIndex
+{
+ NSRange range = NSMakeRange(startIndex, [_attrStr length] - startIndex);
+ if (range.length > 0 && [@"A" isEqualToString:tag]) {
+ NSString *urlString = [element getAttribute:@"href"];
+ NSString *strippedString = [urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+ if (urlString && [urlString length] > 0 && strippedString && [strippedString length] > 0 && ![strippedString hasPrefix:@"#"]) {
+ NSURL *url = core([element ownerDocument])->completeURL(stripLeadingAndTrailingHTMLSpaces(urlString));
+ if (!url)
+ url = core([element ownerDocument])->completeURL(stripLeadingAndTrailingHTMLSpaces(strippedString));
+ if (!url)
+ url = [NSURL _web_URLWithString:strippedString relativeToURL:_baseURL];
+ if (!_flags.isIndexing && !_flags.isTesting)
+ [_attrStr addAttribute:NSLinkAttributeName value:url ? (id)url : (id)urlString range:range];
+ }
+ }
+ if (!_flags.reachedEnd && [self _elementIsBlockLevel:element]) {
+ [_writingDirectionArray removeAllObjects];
+ if ([@"table-cell" isEqualToString:displayVal] && [_textBlocks count] == 0) {
+ [self _newTabForElement:element];
+ } else if ([_textLists count] > 0 && [@"block" isEqualToString:displayVal] && ![@"LI" isEqualToString:tag] && ![@"UL" isEqualToString:tag] && ![@"OL" isEqualToString:tag]) {
+ [self _newLineForElement:element];
+ } else {
+ [self _newParagraphForElement:element tag:tag allowEmpty:(range.length == 0) suppressTrailingSpace:YES];
+ }
+ } else if ([_writingDirectionArray count] > 0) {
+ NSString *bidi = [self _stringForNode:element property:CSSPropertyUnicodeBidi];
+ if (bidi && ([bidi isEqualToString:@"embed"] || [bidi isEqualToString:@"bidi-override"])) {
+ [_writingDirectionArray removeLastObject];
+ }
+ }
+ range = NSMakeRange(startIndex, [_attrStr length] - startIndex);
+ if ([@"table" isEqualToString:displayVal] && [_textTables count] > 0) {
+ NSValue *key = [NSValue valueWithNonretainedObject:[_textTables lastObject]];
+ DOMNode *footer = [_textTableFooters objectForKey:key];
+ while ([_textTables count] < [_textBlocks count] + 1)
+ [_textBlocks removeLastObject];
+ if (footer) {
+ [self _traverseFooterNode:footer depth:depth + 1];
+ [_textTableFooters removeObjectForKey:key];
+ }
+ [_textTables removeLastObject];
+ [_textTableSpacings removeLastObject];
+ [_textTablePaddings removeLastObject];
+ [_textTableRows removeLastObject];
+ [_textTableRowArrays removeLastObject];
+ } else if ([@"table-row" isEqualToString:displayVal] && [_textTables count] > 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 < count; i++) {
+ block = [previousRowArray objectAtIndex:i];
+ if ([block startingColumn] + [block columnSpan] > numberOfColumns) numberOfColumns = [block startingColumn] + [block columnSpan];
+ if ([block startingRow] + [block rowSpan] > rowNumber) [rowArray addObject:block];
+ }
+ count = [rowArray count];
+ openColumn = 0;
+ for (i = 0; i < count; i++) {
+ block = [rowArray objectAtIndex:i];
+ if (openColumn >= [block startingColumn] && openColumn < [block startingColumn] + [block columnSpan]) openColumn = [block startingColumn] + [block columnSpan];
+ }
+ } while (openColumn >= numberOfColumns);
+ if ((NSUInteger)numberOfColumns > [table numberOfColumns])
+ [table setNumberOfColumns:numberOfColumns];
+ [_textTableRows removeLastObject];
+ [_textTableRows addObject:[NSNumber numberWithInteger:rowNumber]];
+ [_textTableRowArrays removeLastObject];
+ [_textTableRowArrays addObject:rowArray];
+ if ([_textTableRowBackgroundColors count] > 0)
+ [_textTableRowBackgroundColors removeLastObject];
+ } else if ([@"table-cell" isEqualToString:displayVal] && [_textBlocks count] > 0) {
+ while ([_textTables count] > [_textBlocks count]) {
+ [_textTables removeLastObject];
+ [_textTableSpacings removeLastObject];
+ [_textTablePaddings removeLastObject];
+ [_textTableRows removeLastObject];
+ [_textTableRowArrays removeLastObject];
+ }
+ [_textBlocks removeLastObject];
+ } else if (([@"UL" isEqualToString:tag] || [@"OL" isEqualToString:tag]) && [_textLists count] > 0) {
+ NSTextList *list = [_textLists lastObject];
+ [self _addMarkersToList:list range:range];
+ [_textLists removeLastObject];
+ } else if ([@"Q" isEqualToString:tag]) {
+ [self _addQuoteForElement:element opening:NO level:--_quoteLevel];
+ } else if ([@"SPAN" isEqualToString:tag]) {
+ NSString *className = [element getAttribute:@"class"];
+ NSMutableString *mutableString;
+ NSUInteger i, count = 0;
+ unichar c;
+ if ([@"Apple-converted-space" isEqualToString:className]) {
+ mutableString = [_attrStr mutableString];
+ for (i = range.location; i < NSMaxRange(range); i++) {
+ c = [mutableString characterAtIndex:i];
+ if (0xa0 == c)
+ [mutableString replaceCharactersInRange:NSMakeRange(i, 1) withString:@" "];
+ }
+ } else if ([@"Apple-converted-tab" isEqualToString:className]) {
+ mutableString = [_attrStr mutableString];
+ for (i = range.location; i < NSMaxRange(range); i++) {
+ NSRange rangeToReplace = NSMakeRange(NSNotFound, 0);
+ c = [mutableString characterAtIndex:i];
+ if (' ' == c || 0xa0 == c) {
+ count++;
+ if (count >= 4 || i + 1 >= NSMaxRange(range))
+ rangeToReplace = NSMakeRange(i + 1 - count, count);
+ } else {
+ if (count > 0)
+ rangeToReplace = NSMakeRange(i - count, count);
+ }
+ if (rangeToReplace.length > 0) {
+ [mutableString replaceCharactersInRange:rangeToReplace withString:@"\t"];
+ range.length -= (rangeToReplace.length - 1);
+ i -= (rangeToReplace.length - 1);
+ if (NSMaxRange(rangeToReplace) <= _domRangeStartIndex) {
+ _domRangeStartIndex -= (rangeToReplace.length - 1);
+ } else if (rangeToReplace.location < _domRangeStartIndex) {
+ _domRangeStartIndex = rangeToReplace.location;
+ }
+ count = 0;
+ }
+ }
+ }
+ }
+}
+
+- (void)_processText:(DOMCharacterData *)text
+{
+ NSString *instr = [text data];
+ NSString *outstr = instr;
+ NSString *whitespaceVal;
+ NSString *transformVal;
+ NSUInteger textLength = [_attrStr length];
+ NSUInteger startOffset = 0;
+ NSUInteger endOffset = [instr length];
+ unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n';
+ BOOL wasSpace = NO;
+ BOOL wasLeading = YES;
+ BOOL suppressLeadingSpace = ((_flags.isSoft && lastChar == ' ') || lastChar == '\n' || lastChar == '\r' || lastChar == '\t' || lastChar == NSParagraphSeparatorCharacter || lastChar == NSLineSeparatorCharacter || lastChar == NSFormFeedCharacter || lastChar == WebNextLineCharacter);
+ NSRange rangeToReplace = NSMakeRange(textLength, 0);
+ CFMutableStringRef mutstr = NULL;
+ whitespaceVal = [self _stringForNode:text property:CSSPropertyWhiteSpace];
+ transformVal = [self _stringForNode:text property:CSSPropertyTextTransform];
+
+ if (_domRange) {
+ if (text == [_domRange startContainer]) {
+ startOffset = (NSUInteger)[_domRange startOffset];
+ _domRangeStartIndex = [_attrStr length];
+ _flags.reachedStart = YES;
+ }
+ if (text == [_domRange endContainer]) {
+ endOffset = (NSUInteger)[_domRange endOffset];
+ _flags.reachedEnd = YES;
+ }
+ if ((startOffset > 0 || endOffset < [instr length]) && endOffset >= startOffset) {
+ instr = [instr substringWithRange:NSMakeRange(startOffset, endOffset - startOffset)];
+ outstr = instr;
+ }
+ }
+ if ([whitespaceVal hasPrefix:@"pre"]) {
+ if (textLength > 0 && [instr length] > 0 && _flags.isSoft) {
+ unichar c = [instr characterAtIndex:0];
+ if (c == '\n' || c == '\r' || c == NSParagraphSeparatorCharacter || c == NSLineSeparatorCharacter || c == NSFormFeedCharacter || c == WebNextLineCharacter)
+ rangeToReplace = NSMakeRange(textLength - 1, 1);
+ }
+ } else {
+ CFStringInlineBuffer inlineBuffer;
+ const unsigned int TextBufferSize = 255;
+
+ unichar buffer[TextBufferSize + 1];
+ NSUInteger i, count = [instr length], idx = 0;
+
+ mutstr = CFStringCreateMutable(NULL, 0);
+ CFStringInitInlineBuffer((CFStringRef)instr, &inlineBuffer, CFRangeMake(0, count));
+ for (i = 0; i < count; i++) {
+ unichar c = CFStringGetCharacterFromInlineBuffer(&inlineBuffer, i);
+ if (c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == 0xc || c == 0x200b) {
+ wasSpace = (!wasLeading || !suppressLeadingSpace);
+ } else {
+ if (wasSpace)
+ buffer[idx++] = ' ';
+ buffer[idx++] = c;
+ if (idx >= TextBufferSize) {
+ CFStringAppendCharacters(mutstr, buffer, idx);
+ idx = 0;
+ }
+ wasSpace = wasLeading = NO;
+ }
+ }
+ if (wasSpace)
+ buffer[idx++] = ' ';
+ if (idx > 0)
+ CFStringAppendCharacters(mutstr, buffer, idx);
+ outstr = (NSString *)mutstr;
+ }
+ if ([outstr length] > 0) {
+ if ([@"capitalize" isEqualToString:transformVal])
+ outstr = [outstr capitalizedString];
+ else if ([@"uppercase" isEqualToString:transformVal])
+ outstr = [outstr uppercaseString];
+ else if ([@"lowercase" isEqualToString:transformVal])
+ outstr = [outstr lowercaseString];
+ [_attrStr replaceCharactersInRange:rangeToReplace withString:outstr];
+ rangeToReplace.length = [outstr length];
+ if (!_flags.isIndexing) {
+ RetainPtr<NSDictionary> attrs;
+ DOMElement *element = (DOMElement *)text;
+ while (element) {
+ // Fill attrs dictionary with attributes from parent nodes, not overwriting ones deeper in the tree
+ if([element nodeType] == DOM_ELEMENT_NODE) {
+ RetainPtr<NSMutableDictionary> newAttrs = adoptNS([[self _attributesForElement:element] mutableCopy]);
+ if (attrs) {
+ // Already-set attributes (from lower in the tree) overwrite the higher ones.
+ [newAttrs addEntriesFromDictionary:attrs.get()];
+ }
+ attrs = newAttrs;
+ }
+ element = (DOMElement *)[element parentNode];
+ }
+ if (!_flags.isTesting && rangeToReplace.length > 0)
+ [_attrStr setAttributes:attrs.get() range:rangeToReplace];
+ }
+ _flags.isSoft = wasSpace;
+ }
+ if (mutstr)
+ CFRelease(mutstr);
+}
+
+- (void)_traverseNode:(DOMNode *)node depth:(NSInteger)depth embedded:(BOOL)embedded
+{
+ unsigned short nodeType;
+ NSArray *childNodes;
+ NSUInteger count;
+ NSUInteger startOffset;
+ NSUInteger endOffset;
+ BOOL isStart = NO;
+ BOOL isEnd = NO;
+
+ if (_flags.reachedEnd)
+ return;
+ if (_domRange && !_flags.reachedStart && _domStartAncestors && ![_domStartAncestors containsObject:node])
+ return;
+
+ nodeType = [node nodeType];
+ childNodes = [self _childrenForNode:node];
+ count = [childNodes count];
+ startOffset = 0;
+ endOffset = count;
+
+ if (_domRange) {
+ if (node == [_domRange startContainer]) {
+ startOffset = (NSUInteger)[_domRange startOffset];
+ isStart = YES;
+ _flags.reachedStart = YES;
+ }
+ if (node == [_domRange endContainer]) {
+ endOffset = (NSUInteger)[_domRange endOffset];
+ isEnd = YES;
+ }
+ }
+
+ if (nodeType == DOM_DOCUMENT_NODE || nodeType == DOM_DOCUMENT_FRAGMENT_NODE) {
+ for (NSUInteger i = 0; i < count; i++) {
+ if (isStart && i == startOffset)
+ _domRangeStartIndex = [_attrStr length];
+ if ((!isStart || startOffset <= i) && (!isEnd || endOffset > i))
+ [self _traverseNode:[childNodes objectAtIndex:i] depth:depth + 1 embedded:embedded];
+ if (isEnd && i + 1 >= endOffset)
+ _flags.reachedEnd = YES;
+ if (_thumbnailLimit > 0 && [_attrStr length] >= _thumbnailLimit)
+ _flags.reachedEnd = YES;
+ if (_flags.reachedEnd) break;
+ }
+ } else if (nodeType == DOM_ELEMENT_NODE) {
+ DOMElement *element = (DOMElement *)node;
+ NSString *tag = [element tagName], *displayVal = [self _stringForNode:element property:CSSPropertyDisplay];
+ if ([self _enterElement:element tag:tag display:displayVal embedded:embedded]) {
+ NSUInteger startIndex = [_attrStr length];
+ if ([self _processElement:element tag:tag display:displayVal depth:depth]) {
+ for (NSUInteger i = 0; i < count; i++) {
+ if (isStart && i == startOffset)
+ _domRangeStartIndex = [_attrStr length];
+ if ((!isStart || startOffset <= i) && (!isEnd || endOffset > i))
+ [self _traverseNode:[childNodes objectAtIndex:i] depth:depth + 1 embedded:embedded];
+ if (isEnd && i + 1 >= endOffset)
+ _flags.reachedEnd = YES;
+ if (_flags.reachedEnd)
+ break;
+ }
+ [self _exitElement:element tag:tag display:displayVal depth:depth startIndex:startIndex];
+ }
+ }
+ } else if (nodeType == DOM_TEXT_NODE || nodeType == DOM_CDATA_SECTION_NODE) {
+ [self _processText:(DOMCharacterData *)node];
+ }
+
+ if (isEnd) _flags.reachedEnd = YES;
+}
+
+- (void)_traverseFooterNode:(DOMNode *)node depth:(NSInteger)depth
+{
+ DOMElement *element = (DOMElement *)node;
+ NSArray *childNodes = [self _childrenForNode:node];
+ NSString *tag = @"TBODY", *displayVal = @"table-row-group";
+ NSUInteger count = [childNodes count];
+ NSUInteger startOffset = 0;
+ NSUInteger endOffset = count;
+ BOOL isStart = NO;
+ BOOL isEnd = NO;
+
+ if (_flags.reachedEnd)
+ return;
+ if (_domRange && !_flags.reachedStart && _domStartAncestors && ![_domStartAncestors containsObject:node])
+ return;
+ if (_domRange) {
+ if (node == [_domRange startContainer]) {
+ startOffset = (NSUInteger)[_domRange startOffset];
+ isStart = YES;
+ _flags.reachedStart = YES;
+ }
+ if (node == [_domRange endContainer]) {
+ endOffset = (NSUInteger)[_domRange endOffset];
+ isEnd = YES;
+ }
+ }
+ if ([self _enterElement:element tag:tag display:displayVal embedded:YES]) {
+ NSUInteger startIndex = [_attrStr length];
+ if ([self _processElement:element tag:tag display:displayVal depth:depth]) {
+ for (NSUInteger i = 0; i < count; i++) {
+ if (isStart && i == startOffset)
+ _domRangeStartIndex = [_attrStr length];
+ if ((!isStart || startOffset <= i) && (!isEnd || endOffset > i))
+ [self _traverseNode:[childNodes objectAtIndex:i] depth:depth + 1 embedded:YES];
+ if (isEnd && i + 1 >= endOffset)
+ _flags.reachedEnd = YES;
+ if (_flags.reachedEnd)
+ break;
+ }
+ [self _exitElement:element tag:tag display:displayVal depth:depth startIndex:startIndex];
+ }
+ }
+ if (isEnd)
+ _flags.reachedEnd = YES;
+}
+
+- (void)_adjustTrailingNewline
+{
+ NSUInteger textLength = [_attrStr length];
+ unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : 0;
+ BOOL alreadyHasTrailingNewline = (lastChar == '\n' || lastChar == '\r' || lastChar == NSParagraphSeparatorCharacter || lastChar == NSLineSeparatorCharacter || lastChar == WebNextLineCharacter);
+ if (_flags.hasTrailingNewline && !alreadyHasTrailingNewline)
+ [_attrStr replaceCharactersInRange:NSMakeRange(textLength, 0) withString:@"\n"];
+}
+
+- (void)_loadFromDOMRange
+{
+ if (-1 == _errorCode) {
+ DOMNode *commonAncestorContainer = [_domRange commonAncestorContainer];
+ DOMNode *ancestorContainer = [_domRange startContainer];
+
+ _domStartAncestors = [[NSMutableArray alloc] init];
+ while (ancestorContainer) {
+ [_domStartAncestors addObject:ancestorContainer];
+ if (ancestorContainer == commonAncestorContainer)
+ break;
+ ancestorContainer = [ancestorContainer parentNode];
+ }
+ _document = [commonAncestorContainer ownerDocument];
+ _dataSource = (DocumentLoader *)core(_document)->frame()->loader().documentLoader();
+ if (_textSizeMultiplier <= 0.0)
+ _textSizeMultiplier = 1;
+ if (_defaultFontSize <= 0.0)
+ _defaultFontSize = 12;
+ if (_minimumFontSize < 1.0)
+ _minimumFontSize = 1;
+ if (_document && _dataSource) {
+ _domRangeStartIndex = 0;
+ _errorCode = 0;
+ [self _traverseNode:commonAncestorContainer depth:0 embedded:NO];
+ if (_domRangeStartIndex > 0 && _domRangeStartIndex <= [_attrStr length])
+ [_attrStr deleteCharactersInRange:NSMakeRange(0, _domRangeStartIndex)];
+ }
+ }
+}
+
+- (void)dealloc
+{
+ [_attrStr release];
+ [_documentAttrs release];
+ [_domRange release];
+ [_domStartAncestors release];
+ [_standardFontFamily release];
+ [_textLists release];
+ [_textBlocks release];
+ [_textTables release];
+ [_textTableFooters release];
+ [_textTableSpacings release];
+ [_textTablePaddings release];
+ [_textTableRows release];
+ [_textTableRowArrays release];
+ [_textTableRowBackgroundColors release];
+ [_attributesForElements release];
+ [_fontCache release];
+ [_writingDirectionArray release];
+ [super dealloc];
+}
+
+- (id)init
+{
+ self = [super init];
+ if (!self)
+ return nil;
+
+ _attrStr = [[NSMutableAttributedString alloc] init];
+ _documentAttrs = [[NSMutableDictionary alloc] init];
+
+ _textLists = [[NSMutableArray alloc] init];
+ _textBlocks = [[NSMutableArray alloc] init];
+ _textTables = [[NSMutableArray alloc] init];
+ _textTableFooters = [[NSMutableDictionary alloc] init];
+ _textTableSpacings = [[NSMutableArray alloc] init];
+ _textTablePaddings = [[NSMutableArray alloc] init];
+ _textTableRows = [[NSMutableArray alloc] init];
+ _textTableRowArrays = [[NSMutableArray alloc] init];
+ _textTableRowBackgroundColors = [[NSMutableArray alloc] init];
+ _attributesForElements = [[NSMutableDictionary alloc] init];
+ _fontCache = [[NSMutableDictionary alloc] init];
+ _writingDirectionArray = [[NSMutableArray alloc] init];
+
+ _textSizeMultiplier = 1;
+ _webViewTextSizeMultiplier = 0;
+ _defaultTabInterval = 36;
+ _defaultFontSize = 12;
+ _minimumFontSize = 1;
+ _errorCode = -1;
+ _indexingLimit = 0;
+ _thumbnailLimit = 0;
+
+ _caches = std::make_unique<HTMLConverterCaches>();
+
+ _flags.isIndexing = (_indexingLimit > 0);
+ _flags.isTesting = 0;
+
+ return self;
+}
+
+- (id)initWithDOMRange:(DOMRange *)domRange
+{
+ self = [self init];
+ if (!self)
+ return nil;
+ _domRange = [domRange retain];
+ return self;
+}
+
+- (NSAttributedString *)attributedString
+{
+ [self _loadFromDOMRange];
+ return (!_errorCode) ? [[_attrStr retain] autorelease] : nil;
+}
+
+
+// This function supports more HTML features than the editing variant below, such as tables.
++ (NSAttributedString *)attributedStringFromRange:(Range*)range
+{
+ RetainPtr<WebHTMLConverter> converter = adoptNS([[WebHTMLConverter alloc] initWithDOMRange:kit(range)]);
+ return [converter attributedString];
+}
+
+#if !PLATFORM(IOS)
+
+// This function uses TextIterator, which makes offsets in its result compatible with HTML editing.
++ (NSAttributedString *)editingAttributedStringFromRange:(Range*)range
+{
+ NSFontManager *fontManager = [NSFontManager sharedFontManager];
+ NSMutableAttributedString *string = [[NSMutableAttributedString alloc] init];
+ NSUInteger stringLength = 0;
+ RetainPtr<NSMutableDictionary> attrs = adoptNS([[NSMutableDictionary alloc] init]);
+
+ for (TextIterator it(range); !it.atEnd(); it.advance()) {
+ RefPtr<Range> currentTextRange = it.range();
+ Node* startContainer = currentTextRange->startContainer();
+ Node* endContainer = currentTextRange->endContainer();
+ int startOffset = currentTextRange->startOffset();
+ int endOffset = currentTextRange->endOffset();
+
+ if (startContainer == endContainer && (startOffset == endOffset - 1)) {
+ Node* node = startContainer->childNode(startOffset);
+ if (node && node->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->renderer();
+ ASSERT(renderer);
+ if (!renderer)
+ continue;
+ const RenderStyle& style = renderer->style();
+ if (style.textDecorationsInEffect() & TextDecorationUnderline)
+ [attrs.get() setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName];
+ if (style.textDecorationsInEffect() & TextDecorationLineThrough)
+ [attrs.get() setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSStrikethroughStyleAttributeName];
+ if (NSFont *font = style.font().primaryFont()->getNSFont())
+ [attrs.get() setObject:font forKey:NSFontAttributeName];
+ else
+ [attrs.get() setObject:[fontManager convertFont:WebDefaultFont() toSize:style.font().primaryFont()->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
+
+@end
+
+#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<ArchiveResource> resource = dataSource->subresource(URL);
+ if (resource) {
+ NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:resource->data()->createNSData().get()] autorelease];
+ NSString *filename = resource->response().suggestedFilename();
+ if (!filename || ![filename length])
+ filename = suggestedFilenameWithMIMEType(resource->url(), resource->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& attr = element->getAttribute(srcAttr);
+ if (!attr.isEmpty()) {
+ NSURL *URL = element->document().completeURL(attr);
+ if (DocumentLoader* loader = element->document().loader())
+ wrapper = fileWrapperForURL(loader, URL);
+ }
+ if (!wrapper) {
+ RenderImage* renderer = toRenderImage(element->renderer());
+ if (renderer->cachedImage() && !renderer->cachedImage()->errorOccurred()) {
+ wrapper = [[NSFileWrapper alloc] initRegularFileWithContents:(NSData *)(renderer->cachedImage()->imageForRenderer(renderer)->getTIFFRepresentation())];
+ [wrapper setPreferredFilename:@"image.tiff"];
+ [wrapper autorelease];
+ }
+ }
+
+ return wrapper;
+}
+
+#endif
+
+namespace WebCore {
+
+NSAttributedString *attributedStringFromRange(Range& range)
+{
+ return [WebHTMLConverter attributedStringFromRange:&range];
+}
+
+#if !PLATFORM(IOS)
+NSAttributedString *editingAttributedStringFromRange(Range& range)
+{
+ return [WebHTMLConverter editingAttributedStringFromRange:&range];
+}
+#endif
+
+}
</ins></span></pre></div>
<a id="trunkSourceWebCoreplatformmacHTMLConverterh"></a>
<div class="delfile"><h4>Deleted: trunk/Source/WebCore/platform/mac/HTMLConverter.h (166146 => 166147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mac/HTMLConverter.h        2014-03-23 21:47:52 UTC (rev 166146)
+++ trunk/Source/WebCore/platform/mac/HTMLConverter.h        2014-03-23 22:14:20 UTC (rev 166147)
</span><span class="lines">@@ -1,42 +0,0 @@
</span><del>-/*
- * 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;
-
-NSAttributedString *attributedStringFromRange(Range&);
-#if !PLATFORM(IOS)
-NSAttributedString *editingAttributedStringFromRange(Range&);
-#endif
-
-}
-
-#endif // HTMLConverter_h
</del></span></pre></div>
<a id="trunkSourceWebCoreplatformmacHTMLConvertermm"></a>
<div class="delfile"><h4>Deleted: trunk/Source/WebCore/platform/mac/HTMLConverter.mm (166146 => 166147)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/mac/HTMLConverter.mm        2014-03-23 21:47:52 UTC (rev 166146)
+++ trunk/Source/WebCore/platform/mac/HTMLConverter.mm        2014-03-23 22:14:20 UTC (rev 166147)
</span><span class="lines">@@ -1,2648 +0,0 @@
</span><del>-/*
- * 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 "config.h"
-#import "HTMLConverter.h"
-
-#import "ArchiveResource.h"
-#import "CachedImage.h"
-#import "ColorMac.h"
-#import "CSSComputedStyleDeclaration.h"
-#import "CSSParser.h"
-#import "CSSPrimitiveValue.h"
-#import "Document.h"
-#import "DocumentLoader.h"
-#import "DOMCSSPrimitiveValueInternal.h"
-#import "DOMDocumentInternal.h"
-#import "DOMElementInternal.h"
-#import "DOMHTMLTableCellElement.h"
-#import "DOMNodeInternal.h"
-#import "DOMPrivate.h"
-#import "DOMRGBColorInternal.h"
-#import "DOMRangeInternal.h"
-#import "Element.h"
-#import "Font.h"
-#import "Frame.h"
-#import "FrameLoader.h"
-#import "HTMLElement.h"
-#import "HTMLNames.h"
-#import "HTMLParserIdioms.h"
-#import "LoaderNSURLExtras.h"
-#import "RGBColor.h"
-#import "RenderImage.h"
-#import "SoftLinking.h"
-#import "StyleProperties.h"
-#import "StyledElement.h"
-#import "TextIterator.h"
-#import <objc/runtime.h>
-#import <wtf/ASCIICType.h>
-
-#if PLATFORM(IOS)
-
-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 = @"NSSuperscript";
-#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 << 0
- UIFontTraitBold = 0x00000002, // 1 << 1
- UIFontTraitThin = (1 << 2),
- UIFontTraitLight = (1 << 3),
- UIFontTraitUltraLight = (1 << 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 << 1),
- NSTextWritingDirectionOverride = (1 << 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;
-
-class HTMLConverterCaches {
-public:
- String propertyValueForNode(Node&, CSSPropertyID );
- bool floatPropertyValueForNode(Node&, CSSPropertyID, float&);
- Color colorPropertyValueForNode(Node&, CSSPropertyID);
-
- bool isBlockElement(Element&);
- bool elementHasOwnBackgroundColor(Element&);
-
- PassRefPtr<CSSValue> computedStylePropertyForElement(Element&, CSSPropertyID);
- PassRefPtr<CSSValue> inlineStylePropertyForElement(Element&, CSSPropertyID);
-
-private:
- HashMap<Element*, std::unique_ptr<ComputedStyleExtractor>> m_computedStyles;
-};
-
-@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
-
-@interface WebHTMLConverter : NSObject {
- NSMutableAttributedString *_attrStr;
- NSMutableDictionary *_documentAttrs;
- NSURL *_baseURL;
- DOMDocument *_document;
- DOMRange *_domRange;
- NSMutableArray *_domStartAncestors;
- WebCore::DocumentLoader *_dataSource;
- NSString *_standardFontFamily;
- CGFloat _textSizeMultiplier;
- CGFloat _webViewTextSizeMultiplier;
- CGFloat _defaultTabInterval;
- CGFloat _defaultFontSize;
- CGFloat _minimumFontSize;
- NSMutableArray *_textLists;
- NSMutableArray *_textBlocks;
- NSMutableArray *_textTables;
- NSMutableDictionary *_textTableFooters;
- NSMutableArray *_textTableSpacings;
- NSMutableArray *_textTablePaddings;
- NSMutableArray *_textTableRows;
- NSMutableArray *_textTableRowArrays;
- NSMutableArray *_textTableRowBackgroundColors;
- NSMutableDictionary *_colorsForNodes;
- NSMutableDictionary *_attributesForElements;
- NSMutableDictionary *_fontCache;
- NSMutableArray *_writingDirectionArray;
- NSUInteger _domRangeStartIndex;
- NSInteger _indexingLimit;
- NSUInteger _thumbnailLimit;
- NSInteger _errorCode;
- NSInteger _quoteLevel;
-
- std::unique_ptr<HTMLConverterCaches> _caches;
-
- struct {
- unsigned int isSoft:1;
- unsigned int reachedStart:1;
- unsigned int reachedEnd:1;
- unsigned int isIndexing:1;
- unsigned int isTesting:1;
- unsigned int hasTrailingNewline:1;
- unsigned int pad:26;
- } _flags;
-}
-
-+ (NSAttributedString *)attributedStringFromRange:(Range*)range;
-#if !PLATFORM(IOS)
-+ (NSAttributedString *)editingAttributedStringFromRange:(Range*)range;
-#endif
-@end
-
-@interface WebHTMLConverter(WebHTMLConverterInternal)
-
-- (id)init;
-- (id)initWithDOMRange:(DOMRange *)domRange;
-- (NSAttributedString *)attributedString;
-
-- (NSString *)_stringForNode:(DOMNode *)node property:(CSSPropertyID)propertyId;
-- (PlatformColor *)_colorForNode:(DOMNode *)node property:(CSSPropertyID)propertyId;
-- (BOOL)_getFloat:(CGFloat *)val forNode:(DOMNode *)node property:(CSSPropertyID)propertyId;
-
-- (void)_traverseNode:(DOMNode *)node depth:(NSInteger)depth embedded:(BOOL)embedded;
-- (void)_traverseFooterNode:(DOMNode *)node depth:(NSInteger)depth;
-
-@end
-
-@implementation WebHTMLConverter
-
-#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:@"Helvetica" 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:@" " options:NSBackwardsSearch];
- NSRange dividingDashRange = [fontName rangeOfString:@"-" options:NSBackwardsSearch];
- dividingRange = (0 < dividingSpaceRange.length && 0 < dividingDashRange.length) ? (dividingSpaceRange.location > dividingDashRange.location ? dividingSpaceRange : dividingDashRange) : (0 < dividingSpaceRange.length ? dividingSpaceRange : dividingDashRange);
-
- while (dividingRange.length > 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 && [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 < [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:@" " options:NSBackwardsSearch];
- dividingDashRange = [familyName rangeOfString:@"-" options:NSBackwardsSearch];
- dividingRange = (0 < dividingSpaceRange.length && 0 < dividingDashRange.length) ? (dividingSpaceRange.location > dividingDashRange.location ? dividingSpaceRange : dividingDashRange) : (0 < dividingSpaceRange.length ? dividingSpaceRange : dividingDashRange);
- }
- }
- }
-#if PLATFORM(IOS)
- if (!font)
- font = [PlatformFontClass systemFontOfSize:size];
-#else
- if (!font)
- font = [NSFont fontWithName:@"Times" 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;
-}
-
-+ (NSParagraphStyle *)defaultParagraphStyle
-{
- static NSMutableParagraphStyle *defaultParagraphStyle = nil;
- if (!defaultParagraphStyle) {
- defaultParagraphStyle = [[PlatformNSParagraphStyle defaultParagraphStyle] mutableCopy];
- [defaultParagraphStyle setDefaultTabInterval:36];
- [defaultParagraphStyle setTabStops:[NSArray array]];
- }
- return defaultParagraphStyle;
-}
-
-- (NSArray *)_childrenForNode:(DOMNode *)node
-{
- NSMutableArray *array = [NSMutableArray array];
- DOMNode *child = [node firstChild];
- while (child) {
- [array addObject:child];
- child = [child nextSibling];
- }
- return array;
-}
-
-PassRefPtr<CSSValue> HTMLConverterCaches::computedStylePropertyForElement(Element& element, CSSPropertyID propertyId)
-{
- if (propertyId == CSSPropertyInvalid)
- return nullptr;
-
- auto result = m_computedStyles.add(&element, nullptr);
- if (result.isNewEntry)
- result.iterator->value = std::make_unique<ComputedStyleExtractor>(&element, true);
- ComputedStyleExtractor& computedStyle = *result.iterator->value;
- return computedStyle.propertyValue(propertyId);
-}
-
-PassRefPtr<CSSValue> HTMLConverterCaches::inlineStylePropertyForElement(Element& element, CSSPropertyID propertyId)
-{
- if (propertyId == CSSPropertyInvalid || !element.isStyledElement())
- return nullptr;
- const StyleProperties* properties = toStyledElement(element).inlineStyle();
- if (!properties)
- return nullptr;
- return properties->getPropertyCSSValue(propertyId);
-}
-
-static bool stringFromCSSValue(CSSValue& value, String& 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& node, CSSPropertyID propertyId)
-{
- if (!node.isElementNode()) {
- if (Node* parent = node.parentNode())
- return propertyValueForNode(*parent, propertyId);
- return String();
- }
-
- bool inherit = false;
- Element& element = toElement(node);
- if (RefPtr<CSSValue> value = computedStylePropertyForElement(element, propertyId)) {
- String result;
- if (stringFromCSSValue(*value, result))
- return result;
- }
-
- if (RefPtr<CSSValue> value = inlineStylePropertyForElement(element, propertyId)) {
- String result;
- if (value->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 "none";
- 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 "block";
- else if (element.hasTagName(liTag))
- return "list-item";
- else if (element.hasTagName(tableTag))
- return "table";
- else if (element.hasTagName(trTag))
- return "table-row";
- else if (element.hasTagName(thTag) || element.hasTagName(tdTag))
- return "table-cell";
- else if (element.hasTagName(theadTag))
- return "table-header-group";
- else if (element.hasTagName(tbodyTag))
- return "table-row-group";
- else if (element.hasTagName(tfootTag))
- return "table-footer-group";
- else if (element.hasTagName(colTag))
- return "table-column";
- else if (element.hasTagName(colgroupTag))
- return "table-column-group";
- else if (element.hasTagName(captionTag))
- return "table-caption";
- break;
- case CSSPropertyWhiteSpace:
- if (element.hasTagName(preTag))
- return "pre";
- inherit = true;
- break;
- case CSSPropertyFontStyle:
- if (element.hasTagName(iTag) || element.hasTagName(citeTag) || element.hasTagName(emTag) || element.hasTagName(varTag) || element.hasTagName(addressTag))
- return "italic";
- inherit = true;
- break;
- case CSSPropertyFontWeight:
- if (element.hasTagName(bTag) || element.hasTagName(strongTag) || element.hasTagName(thTag))
- return "bolder";
- inherit = true;
- break;
- case CSSPropertyTextDecoration:
- if (element.hasTagName(uTag) || element.hasTagName(insTag))
- return "underline";
- else if (element.hasTagName(sTag) || element.hasTagName(strikeTag) || element.hasTagName(delTag))
- return "line-through";
- inherit = true; // FIXME: This is not strictly correct
- break;
- case CSSPropertyTextAlign:
- if (element.hasTagName(centerTag) || element.hasTagName(captionTag) || element.hasTagName(thTag))
- return "center";
- inherit = true;
- break;
- case CSSPropertyVerticalAlign:
- if (element.hasTagName(supTag))
- return "super";
- else if (element.hasTagName(subTag))
- return "sub";
- else if (element.hasTagName(theadTag) || element.hasTagName(tbodyTag) || element.hasTagName(tfootTag))
- return "middle";
- 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();
-}
-
-- (NSString *)_stringForNode:(DOMNode *)node property:(CSSPropertyID)propertyId
-{
- Node* coreNode = core(node);
- if (!coreNode)
- return nil;
- String result = _caches->propertyValueForNode(*coreNode, propertyId);
- if (!result.length())
- return nil;
- return result;
-}
-
-static inline bool floatValueFromPrimitiveValue(CSSPrimitiveValue& primitiveValue, float& 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& node, CSSPropertyID propertyId, float& result)
-{
- if (!node.isElementNode()) {
- if (ContainerNode* parent = node.parentNode())
- return floatPropertyValueForNode(*parent, propertyId, result);
- return false;
- }
-
- Element& element = toElement(node);
- if (RefPtr<CSSValue> value = computedStylePropertyForElement(element, propertyId)) {
- if (value->isPrimitiveValue() && floatValueFromPrimitiveValue(toCSSPrimitiveValue(*value), result))
- return true;
- }
-
- bool inherit = false;
- if (RefPtr<CSSValue> value = inlineStylePropertyForElement(element, propertyId)) {
- if (value->isPrimitiveValue() && floatValueFromPrimitiveValue(toCSSPrimitiveValue(*value), result))
- return true;
- if (value->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;
-}
-
-- (BOOL)_getFloat:(CGFloat *)val forNode:(DOMNode *)node property:(CSSPropertyID)propertyId
-{
- Node* coreNode = core(node);
- if (!coreNode)
- return NO;
- float result;
- if (!_caches->floatPropertyValueForNode(*coreNode, propertyId, result))
- return NO;
- if (val)
- *val = result;
- return YES;
-}
-
-static NSString *_NSFirstPathForDirectoriesInDomains(NSSearchPathDirectory directory, NSSearchPathDomainMask domainMask, BOOL expandTilde)
-{
- NSArray *array = NSSearchPathForDirectoriesInDomains(directory, domainMask, expandTilde);
- return [array count] >= 1 ? [array objectAtIndex:0] : nil;
-}
-
-static NSString *_NSSystemLibraryPath(void)
-{
- return _NSFirstPathForDirectoriesInDomains(NSLibraryDirectory, NSSystemDomainMask, YES);
-}
-
-- (NSBundle *)_webKitBundle
-{
- NSBundle *bundle = [NSBundle bundleWithIdentifier:@"com.apple.WebKit"];
- if (!bundle)
- bundle = [NSBundle bundleWithPath:[_NSSystemLibraryPath() stringByAppendingPathComponent:@"Frameworks/WebKit.framework"]];
- return bundle;
-}
-
-#if PLATFORM(IOS)
-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:@"("];
- NSRange closeParenRange = [shadowStyle rangeOfString:@")"];
- NSRange firstRange = NSMakeRange(NSNotFound, 0);
- NSRange secondRange = NSMakeRange(NSNotFound, 0);
- NSRange thirdRange = NSMakeRange(NSNotFound, 0);
- NSRange spaceRange;
- if (openParenRange.length > 0 && closeParenRange.length > 0 && NSMaxRange(openParenRange) < closeParenRange.location) {
- NSArray *components = [[shadowStyle substringWithRange:NSMakeRange(NSMaxRange(openParenRange), closeParenRange.location - NSMaxRange(openParenRange))] componentsSeparatedByString:@","];
- if ([components count] >= 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] >= 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:@"px"];
- if (firstRange.length > 0 && NSMaxRange(firstRange) < shadowStyleLength)
- secondRange = [shadowStyle rangeOfString:@"px" options:0 range:NSMakeRange(NSMaxRange(firstRange), shadowStyleLength - NSMaxRange(firstRange))];
- if (secondRange.length > 0 && NSMaxRange(secondRange) < shadowStyleLength)
- thirdRange = [shadowStyle rangeOfString:@"px" options:0 range:NSMakeRange(NSMaxRange(secondRange), shadowStyleLength - NSMaxRange(secondRange))];
- if (firstRange.location > 0 && firstRange.length > 0 && secondRange.length > 0 && thirdRange.length > 0) {
- spaceRange = [shadowStyle rangeOfString:@" " 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:@" " 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:@" " 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& element)
-{
- String displayValue = propertyValueForNode(element, CSSPropertyDisplay);
- if (displayValue == "block" || displayValue == "list-item" || displayValue.startsWith("table"))
- return true;
- String floatValue = propertyValueForNode(element, CSSPropertyFloat);
- if (floatValue == "left" || floatValue == "right")
- return true;
- return false;
-}
-
-bool HTMLConverterCaches::elementHasOwnBackgroundColor(Element& 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("table");
-}
-
-- (BOOL)_elementIsBlockLevel:(DOMElement *)element
-{
- return element && _caches->isBlockElement(*core(element));
-}
-
-- (BOOL)_elementHasOwnBackgroundColor:(DOMElement *)element
-{
- return element && _caches->elementHasOwnBackgroundColor(*core(element));
-}
-
-- (DOMElement *)_blockLevelElementForNode:(DOMNode *)node
-{
- DOMElement *element = (DOMElement *)node;
- while (element && [element nodeType] != DOM_ELEMENT_NODE)
- element = (DOMElement *)[element parentNode];
- if (element && ![self _elementIsBlockLevel:element])
- element = [self _blockLevelElementForNode:[element 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 < ColorEpsilon && green < ColorEpsilon && blue < ColorEpsilon && (ignoreBlack || alpha < ColorEpsilon))
- return Color();
-
- return color;
-}
-
-Color HTMLConverterCaches::colorPropertyValueForNode(Node& node, CSSPropertyID propertyId)
-{
- if (!node.isElementNode()) {
- if (Node* parent = node.parentNode())
- return colorPropertyValueForNode(*parent, propertyId);
- return Color();
- }
-
- Element& element = toElement(node);
- if (RefPtr<CSSValue> value = computedStylePropertyForElement(element, propertyId)) {
- if (value->isPrimitiveValue() && toCSSPrimitiveValue(*value).isRGBColor())
- return normalizedColor(Color(toCSSPrimitiveValue(*value).getRGBA32Value()), propertyId == CSSPropertyColor);
- }
-
- bool inherit = false;
- if (RefPtr<CSSValue> value = inlineStylePropertyForElement(element, propertyId)) {
- if (value->isPrimitiveValue() && toCSSPrimitiveValue(*value).isRGBColor())
- return normalizedColor(Color(toCSSPrimitiveValue(*value).getRGBA32Value()), propertyId == CSSPropertyColor);
- if (value->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 *)_colorForNode:(DOMNode *)node property:(CSSPropertyID)propertyId
-{
- Node* coreNode = core(node);
- if (!coreNode)
- return nil;
- Color result = _caches->colorPropertyValueForNode(*coreNode, propertyId);
- if (!result.isValid())
- return nil;
- PlatformColor *platformResult = _platformColor(result);
- if ([[PlatformColorClass clearColor] isEqual:platformResult] || ([platformResult alphaComponent] == 0.0))
- return nil;
- return platformResult;
-}
-
-#define UIFloatIsZero(number) (fabs(number - 0) < FLT_EPSILON)
-
-- (NSDictionary *)_computedAttributesForElement:(DOMElement *)element
-{
- DOMElement *blockElement = [self _blockLevelElementForNode:element];
- NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
-#if !PLATFORM(IOS)
- NSFontManager *fontManager = [NSFontManager sharedFontManager];
-#endif
- NSString *textDecoration = [self _stringForNode:element property:CSSPropertyTextDecoration];
- NSString *verticalAlign = [self _stringForNode:element property:CSSPropertyVerticalAlign];
- NSString *textShadow = [self _stringForNode:element property:CSSPropertyTextShadow];
- NSString *fontLigatures = [self _stringForNode:element property:CSSPropertyWebkitFontVariantLigatures];
- NSString *fontKerning = [self _stringForNode:element property:CSSPropertyWebkitFontKerning];
- NSString *letterSpacing = [self _stringForNode:element property:CSSPropertyLetterSpacing];
- CGFloat fontSize = 0;
- CGFloat baselineOffset = 0;
- CGFloat strokeWidth = 0.0;
- PlatformFont *font = nil;
- PlatformFont *actualFont = (PlatformFont *)[element _font];
- PlatformColor *foregroundColor = [self _colorForNode:element property:CSSPropertyColor];
- PlatformColor *backgroundColor = [self _colorForNode:element property:CSSPropertyBackgroundColor];
- PlatformColor *strokeColor = [self _colorForNode:element property:CSSPropertyWebkitTextStrokeColor];
-
- if (![self _getFloat:&fontSize forNode:element property:CSSPropertyFontSize] || fontSize <= 0.0)
- fontSize = _defaultFontSize;
- fontSize *= _textSizeMultiplier;
- if (fontSize < _minimumFontSize) fontSize = _minimumFontSize;
- if (fabs(floor(2.0 * fontSize + 0.5) / 2.0 - fontSize) < 0.05)
- fontSize = (CGFloat)floor(2.0 * fontSize + 0.5) / 2;
- else if (fabs(floor(10.0 * fontSize + 0.5) / 10.0 - fontSize) < 0.005)
- fontSize = (CGFloat)floor(10.0 * fontSize + 0.5) / 10;
-
- if (fontSize <= 0.0)
- fontSize = 12;
-
-#if PLATFORM(IOS)
- if (actualFont)
- font = [actualFont fontWithSize:fontSize];
-#else
- if (actualFont)
- font = [fontManager convertFont:actualFont toSize:fontSize];
-#endif
- if (!font) {
- NSString *fontName = [[self _stringForNode:element property:CSSPropertyFontFamily] capitalizedString];
- NSString *fontStyle = [self _stringForNode:element property:CSSPropertyFontStyle];
- NSString *fontWeight = [self _stringForNode:element property:CSSPropertyFontWeight];
-#if !PLATFORM(IOS)
- NSString *fontVariant = [self _stringForNode:element property:CSSPropertyFontVariant];
-#endif
- if (!fontName)
- fontName = _standardFontFamily;
- if (fontName)
- font = _fontForNameAndSize(fontName, fontSize, _fontCache);
- if (!font)
- font = [PlatformFontClass fontWithName:@"Times" size:fontSize];
- if ([@"italic" isEqualToString:fontStyle] || [@"oblique" isEqualToString:fontStyle]) {
- 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;
- }
- if ([fontWeight hasPrefix:@"bold"] || [fontWeight integerValue] >= 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 ([@"small-caps" isEqualToString:fontVariant]) {
- // ??? 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 && ![self _elementHasOwnBackgroundColor:element])
- [attrs setObject:backgroundColor forKey:NSBackgroundColorAttributeName];
-
- if ([self _getFloat:&strokeWidth forNode:element property:CSSPropertyWebkitTextStrokeWidth]) {
- float textStrokeWidth = strokeWidth / ([font pointSize] * 0.01);
- [attrs setObject:[NSNumber numberWithDouble:textStrokeWidth] forKey:NSStrokeWidthAttributeName];
- }
- if(strokeColor)
- [attrs setObject:strokeColor forKey:NSStrokeColorAttributeName];
- if (fontKerning || letterSpacing) {
- if ([fontKerning rangeOfString:@"none"].location != NSNotFound)
- [attrs setObject:@0.0 forKey:NSKernAttributeName];
- else {
- double kernVal = letterSpacing ? [letterSpacing doubleValue] : 0.0;
- if (UIFloatIsZero(kernVal))
- [attrs setObject:@0.0 forKey:NSKernAttributeName]; // auto and normal, the other possible values, are both "kerning enabled"
- else
- [attrs setObject:[NSNumber numberWithDouble:kernVal] forKey:NSKernAttributeName];
- }
- }
- if (fontLigatures) {
- if ([fontLigatures rangeOfString:@"normal"].location != NSNotFound)
- ; // default: whatever the system decides to do
- else if ([fontLigatures rangeOfString:@"common-ligatures"].location != NSNotFound)
- [attrs setObject:@1 forKey:NSLigatureAttributeName]; // explicitly enabled
- else if ([fontLigatures rangeOfString:@"no-common-ligatures"].location != NSNotFound)
- [attrs setObject:@0 forKey:NSLigatureAttributeName]; // explicitly disabled
- }
-
- if (textDecoration && [textDecoration length] > 4) {
- if ([textDecoration rangeOfString:@"underline"].location != NSNotFound)
- [attrs setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName];
- if ([textDecoration rangeOfString:@"line-through"].location != NSNotFound)
- [attrs setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSStrikethroughStyleAttributeName];
- }
- if (verticalAlign) {
- if ([verticalAlign rangeOfString:@"super"].location != NSNotFound)
- [attrs setObject:[NSNumber numberWithInteger:1] forKey:NSSuperscriptAttributeName];
- if ([verticalAlign rangeOfString:@"sub"].location != NSNotFound)
- [attrs setObject:[NSNumber numberWithInteger:-1] forKey:NSSuperscriptAttributeName];
- }
- if ([self _getFloat:&baselineOffset forNode:element property:CSSPropertyVerticalAlign])
- [attrs setObject:[NSNumber numberWithDouble:baselineOffset] forKey:NSBaselineOffsetAttributeName];
- if (textShadow && [textShadow length] > 4) {
- NSShadow *shadow = _shadowForShadowStyle(textShadow);
- if (shadow)
- [attrs setObject:shadow forKey:NSShadowAttributeName];
- }
- if (element != blockElement && [_writingDirectionArray count] > 0)
- [attrs setObject:[NSArray arrayWithArray:_writingDirectionArray] forKey:NSWritingDirectionAttributeName];
-
- if (blockElement) {
- NSMutableParagraphStyle *paragraphStyle = [[[self class] defaultParagraphStyle] mutableCopy];
- NSString *blockTag = [blockElement tagName];
- BOOL isParagraph = ([@"P" isEqualToString:blockTag] || [@"LI" isEqualToString:blockTag] || ([blockTag hasPrefix:@"H"] && 2 == [blockTag length]));
- NSString *textAlign = [self _stringForNode:blockElement property:CSSPropertyTextAlign];
- NSString *direction = [self _stringForNode:blockElement property:CSSPropertyDirection];
- NSString *hyphenation = [self _stringForNode:blockElement property:CSSPropertyWebkitHyphens];
- CGFloat leftMargin = 0;
- CGFloat rightMargin = 0;
- CGFloat bottomMargin = 0;
- CGFloat textIndent = 0;
- CGFloat lineHeight = 0;
- if (textAlign) {
- // WebKit can return -khtml-left, -khtml-right, -khtml-center
- if ([textAlign hasSuffix:@"left"])
- [paragraphStyle setAlignment:NSTextAlignmentLeft];
- else if ([textAlign hasSuffix:@"right"])
- [paragraphStyle setAlignment:NSTextAlignmentRight];
- else if ([textAlign hasSuffix:@"center"])
- [paragraphStyle setAlignment:NSTextAlignmentCenter];
- else if ([textAlign hasSuffix:@"justify"])
- [paragraphStyle setAlignment:NSTextAlignmentJustified];
- }
- if (direction) {
- if ([direction isEqualToString:@"ltr"])
- [paragraphStyle setBaseWritingDirection:NSWritingDirectionLeftToRight];
- else if ([direction isEqualToString:@"rtl"])
- [paragraphStyle setBaseWritingDirection:NSWritingDirectionRightToLeft];
- }
- if(hyphenation) {
- if ([hyphenation isEqualToString:@"auto"])
- [paragraphStyle setHyphenationFactor:1.0];
- else
- [paragraphStyle setHyphenationFactor:0.0];
- }
- if ([blockTag hasPrefix:@"H"] && 2 == [blockTag length]) {
- NSInteger headerLevel = [blockTag characterAtIndex:1] - '0';
- if (1 <= headerLevel && headerLevel <= 6)
- [paragraphStyle setHeaderLevel:headerLevel];
- }
- if (isParagraph) {
- if ([self _getFloat:&leftMargin forNode:blockElement property:CSSPropertyMarginLeft] && leftMargin > 0.0)
- [paragraphStyle setHeadIndent:leftMargin];
- if ([self _getFloat:&textIndent forNode:blockElement property:CSSPropertyTextIndent])
- [paragraphStyle setFirstLineHeadIndent:[paragraphStyle headIndent] + textIndent];
- if ([self _getFloat:&rightMargin forNode:blockElement property:CSSPropertyMarginRight] && rightMargin > 0.0)
- [paragraphStyle setTailIndent:-rightMargin];
- if ([self _getFloat:&bottomMargin forNode:blockElement property:CSSPropertyMarginBottom] && bottomMargin > 0.0)
- [paragraphStyle setParagraphSpacing:bottomMargin];
- }
- if (_webViewTextSizeMultiplier > 0.0 && [self _getFloat:&lineHeight forNode:element property:CSSPropertyLineHeight] && lineHeight > 0.0)
- [paragraphStyle setMinimumLineHeight:lineHeight / _webViewTextSizeMultiplier];
- if ([_textLists count] > 0)
- [paragraphStyle setTextLists:_textLists];
- if ([_textBlocks count] > 0)
- [paragraphStyle setTextBlocks:_textBlocks];
- [attrs setObject:paragraphStyle forKey:NSParagraphStyleAttributeName];
- [paragraphStyle release];
- }
- return attrs;
-}
-
-- (NSDictionary *)_attributesForElement:(DOMElement *)element
-{
- NSDictionary *result;
- if (element) {
- result = [_attributesForElements objectForKey:element];
- if (!result) {
- result = [self _computedAttributesForElement:element];
- [_attributesForElements setObject:result forKey:element];
- }
- } else
- result = [NSDictionary dictionary];
- return result;
-
-}
-
-- (void)_newParagraphForElement:(DOMElement *)element tag:(NSString *)tag allowEmpty:(BOOL)flag suppressTrailingSpace:(BOOL)suppress
-{
- NSUInteger textLength = [_attrStr length];
- unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n';
- NSRange rangeToReplace = (suppress && _flags.isSoft && (lastChar == ' ' || lastChar == NSLineSeparatorCharacter)) ? NSMakeRange(textLength - 1, 1) : NSMakeRange(textLength, 0);
- BOOL needBreak = (flag || lastChar != '\n');
- if (needBreak) {
- NSString *string = (([@"BODY" isEqualToString:tag] || [@"HTML" isEqualToString:tag]) ? @"" : @"\n");
- [_writingDirectionArray removeAllObjects];
- [_attrStr replaceCharactersInRange:rangeToReplace withString:string];
- if (rangeToReplace.location < _domRangeStartIndex)
- _domRangeStartIndex += [string length] - rangeToReplace.length;
- rangeToReplace.length = [string length];
- if (!_flags.isIndexing) {
- NSDictionary *attrs = [self _attributesForElement:element];
- if (!_flags.isTesting && rangeToReplace.length > 0)
- [_attrStr setAttributes:attrs range:rangeToReplace];
- }
- _flags.isSoft = YES;
- }
-}
-
-- (void)_newLineForElement:(DOMElement *)element
-{
- unichar c = NSLineSeparatorCharacter;
- RetainPtr<NSString> string = adoptNS([[NSString alloc] initWithCharacters:&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 < _domRangeStartIndex) _domRangeStartIndex += rangeToReplace.length;
- if (!_flags.isIndexing) {
- NSDictionary *attrs = [self _attributesForElement:element];
- if (!_flags.isTesting && rangeToReplace.length > 0)
- [_attrStr setAttributes:attrs range:rangeToReplace];
- }
- _flags.isSoft = YES;
-}
-
-- (void)_newTabForElement:(DOMElement *)element
-{
- NSString *string = @"\t";
- NSUInteger textLength = [_attrStr length];
- unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n';
- NSRange rangeToReplace = (_flags.isSoft && lastChar == ' ') ? NSMakeRange(textLength - 1, 1) : NSMakeRange(textLength, 0);
- [_attrStr replaceCharactersInRange:rangeToReplace withString:string];
- rangeToReplace.length = [string length];
- if (rangeToReplace.location < _domRangeStartIndex)
- _domRangeStartIndex += rangeToReplace.length;
- if (!_flags.isIndexing) {
- NSDictionary *attrs = [self _attributesForElement:element];
- if (!_flags.isTesting && rangeToReplace.length > 0)
- [_attrStr setAttributes:attrs range:rangeToReplace];
- }
- _flags.isSoft = YES;
-}
-
-- (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("MFWebMessageDocument");
- if (_WebMessageDocumentClass && ![_WebMessageDocumentClass respondsToSelector:@selector(document:attachment:forURL:)])
- _WebMessageDocumentClass = Nil;
- lookedUpClass = YES;
- }
- return _WebMessageDocumentClass;
-}
-
-- (BOOL)_addAttachmentForElement:(DOMElement *)element URL:(NSURL *)url needsParagraph:(BOOL)needsParagraph usePlaceholder:(BOOL)flag
-{
- BOOL retval = NO, notFound = NO;
- NSFileWrapper *fileWrapper = nil;
- Frame* frame = core([element ownerDocument])->frame();
- DocumentLoader *dataSource = frame->loader().frameHasLoaded() ? frame->loader().documentLoader() : 0;
- BOOL ignoreOrientation = YES;
-
- if (_flags.isIndexing)
- return NO;
- if ([url isFileURL]) {
- NSString *path = [[url path] stringByStandardizingPath];
- if (path)
- fileWrapper = [[[NSFileWrapper alloc] initWithURL:url options:0 error:NULL] autorelease];
- }
- if (!fileWrapper) {
- RefPtr<ArchiveResource> resource = dataSource->subresource(url);
- if (!resource)
- resource = dataSource->subresource(url);
-
- const String& mimeType = resource->mimeType();
- if (flag && resource && mimeType == "text/html")
- notFound = YES;
- if (resource && !notFound) {
- fileWrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:resource->data()->createNSData().get()] autorelease];
- [fileWrapper setPreferredFilename:suggestedFilenameWithMIMEType(url, mimeType)];
- }
- }
-#if !PLATFORM(IOS)
- if (!fileWrapper && !notFound) {
- fileWrapper = fileWrapperForURL(dataSource, url);
- if (flag && fileWrapper && [[[[fileWrapper preferredFilename] pathExtension] lowercaseString] hasPrefix:@"htm"]) notFound = YES;
- if (notFound) fileWrapper = nil;
- }
- if (!fileWrapper && !notFound) {
- fileWrapper = fileWrapperForURL(_dataSource, url);
- if (flag && fileWrapper && [[[[fileWrapper preferredFilename] pathExtension] lowercaseString] hasPrefix:@"htm"]) notFound = YES;
- if (notFound) fileWrapper = nil;
- }
-#endif
- if (!fileWrapper && !notFound && url) {
- // Special handling for Mail attachments, until WebKit provides a standard way to get the data.
- Class WebMessageDocumentClass = [self _WebMessageDocumentClass];
- if (WebMessageDocumentClass) {
- NSTextAttachment *mimeTextAttachment = nil;
- [WebMessageDocumentClass document:NULL attachment:&mimeTextAttachment forURL:url];
- if (mimeTextAttachment && [mimeTextAttachment respondsToSelector:@selector(fileWrapper)]) {
- fileWrapper = [mimeTextAttachment performSelector:@selector(fileWrapper)];
- ignoreOrientation = NO;
- }
- }
- }
- if (fileWrapper || flag) {
- NSUInteger textLength = [_attrStr length];
- RetainPtr<NSTextAttachment> attachment = adoptNS([[PlatformNSTextAttachment alloc] initWithFileWrapper:fileWrapper]);
-#if PLATFORM(IOS)
- NSString *vAlign = [self _stringForNode:element property:CSSPropertyVerticalAlign];
- attachment.get().bounds = CGRectMake(0, ([vAlign floatValue] / 100.) * element.clientHeight, element.clientWidth, element.clientHeight);
-#endif
- RetainPtr<NSString> string = adoptNS([[NSString alloc] initWithFormat:(needsParagraph ? @"%C\n" : @"%C"), static_cast<unichar>(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 = [[self _webKitBundle] URLForResource:@"missing_image" withExtension:@"tiff"];
- ASSERT_WITH_MESSAGE(missingImageURL != nil, "Unable to find missing_image.tiff!");
- 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 < _domRangeStartIndex)
- _domRangeStartIndex += rangeToReplace.length;
- attrs = [self _attributesForElement:element];
- if (!_flags.isTesting && rangeToReplace.length > 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)_addQuoteForElement:(DOMElement *)element opening:(BOOL)opening level:(NSInteger)level
-{
- unichar c = ((level % 2) == 0) ? (opening ? 0x201c : 0x201d) : (opening ? 0x2018 : 0x2019);
- RetainPtr<NSString> string = adoptNS([[NSString alloc] initWithCharacters:&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 < _domRangeStartIndex)
- _domRangeStartIndex += rangeToReplace.length;
- if (!_flags.isIndexing) {
- RetainPtr<NSDictionary> attrs = [self _attributesForElement:element];
- if (!_flags.isTesting && rangeToReplace.length > 0)
- [_attrStr setAttributes:attrs.get() range:rangeToReplace];
- }
- _flags.isSoft = NO;
-}
-
-- (void)_addValue:(NSString *)value forElement:(DOMElement *)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 < _domRangeStartIndex)
- _domRangeStartIndex += rangeToReplace.length;
- if (!_flags.isIndexing) {
- RetainPtr<NSDictionary> attrs = [self _attributesForElement:element];
- if (!_flags.isTesting && rangeToReplace.length > 0)
- [_attrStr setAttributes:attrs.get() range:rangeToReplace];
- }
- _flags.isSoft = NO;
- }
-}
-
-- (void)_fillInBlock:(NSTextBlock *)block forElement:(DOMElement *)element backgroundColor:(PlatformColor *)backgroundColor extraMargin:(CGFloat)extraMargin extraPadding:(CGFloat)extraPadding isTable:(BOOL)isTable
-{
- CGFloat val = 0;
- PlatformColor *color = nil;
- BOOL isTableCellElement = [element isKindOfClass:[DOMHTMLTableCellElement class]];
- NSString *width = isTableCellElement ? [(DOMHTMLTableCellElement *)element width] : [element getAttribute:@"width"];
-
- if ((width && [width length]) || !isTable) {
- if ([self _getFloat:&val forNode:element property:CSSPropertyWidth])
- [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockWidth];
- }
-
- if ([self _getFloat:&val forNode:element property:CSSPropertyMinWidth])
- [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMinimumWidth];
- if ([self _getFloat:&val forNode:element property:CSSPropertyMaxWidth])
- [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMaximumWidth];
- if ([self _getFloat:&val forNode:element property:CSSPropertyMinHeight])
- [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMinimumHeight];
- if ([self _getFloat:&val forNode:element property:CSSPropertyMaxHeight])
- [block setValue:val type:NSTextBlockAbsoluteValueType forDimension:NSTextBlockMaximumHeight];
-
- if ([self _getFloat:&val forNode:element property:CSSPropertyPaddingLeft])
- [block setWidth:val + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinXEdge];
- else [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinXEdge];
- if ([self _getFloat:&val forNode:element property:CSSPropertyPaddingTop])
- [block setWidth:val + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinYEdge]; else [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMinYEdge];
- if ([self _getFloat:&val forNode:element property:CSSPropertyPaddingRight])
- [block setWidth:val + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxXEdge]; else [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxXEdge];
- if ([self _getFloat:&val forNode:element property:CSSPropertyPaddingBottom])
- [block setWidth:val + extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxYEdge]; else [block setWidth:extraPadding type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockPadding edge:NSMaxYEdge];
-
- if ([self _getFloat:&val forNode:element property:CSSPropertyBorderLeftWidth])
- [block setWidth:val type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMinXEdge];
- if ([self _getFloat:&val forNode:element property:CSSPropertyBorderTopWidth])
- [block setWidth:val type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMinYEdge];
- if ([self _getFloat:&val forNode:element property:CSSPropertyBorderRightWidth])
- [block setWidth:val type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMaxXEdge];
- if ([self _getFloat:&val forNode:element property:CSSPropertyBorderBottomWidth])
- [block setWidth:val type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockBorder edge:NSMaxYEdge];
-
- if ([self _getFloat:&val forNode:element property:CSSPropertyMarginLeft])
- [block setWidth:val + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinXEdge]; else [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinXEdge];
- if ([self _getFloat:&val forNode:element property:CSSPropertyMarginTop])
- [block setWidth:val + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinYEdge]; else [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMinYEdge];
- if ([self _getFloat:&val forNode:element property:CSSPropertyMarginRight])
- [block setWidth:val + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxXEdge]; else [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxXEdge];
- if ([self _getFloat:&val forNode:element property:CSSPropertyMarginBottom])
- [block setWidth:val + extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxYEdge]; else [block setWidth:extraMargin type:NSTextBlockAbsoluteValueType forLayer:NSTextBlockMargin edge:NSMaxYEdge];
-
- if ((color = [self _colorForNode:element property:CSSPropertyBackgroundColor]))
- [block setBackgroundColor:color];
- if (!color && backgroundColor) [block setBackgroundColor:backgroundColor];
- if ((color = [self _colorForNode:element property:CSSPropertyBorderLeftColor]))
- [block setBorderColor:color forEdge:NSMinXEdge];
- if ((color = [self _colorForNode:element property:CSSPropertyBorderTopColor]))
- [block setBorderColor:color forEdge:NSMinYEdge];
- if ((color = [self _colorForNode:element property:CSSPropertyBorderRightColor]))
- [block setBorderColor:color forEdge:NSMaxXEdge];
- if ((color = [self _colorForNode:element property: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<NSDateComponents> dateComponents = adoptNS([[NSDateComponents alloc] init]);
-
- // Set the time zone to GMT
- [dateComponents setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
-
- NSInteger year = 0;
- while (*p && isASCIIDigit(*p))
- year = 10 * year + *p++ - '0';
- if (*p++ != '-')
- return nil;
- [dateComponents setYear:year];
-
- int8_t component;
- if (!read2DigitNumber(&p, &component) || *p++ != '-')
- return nil;
- [dateComponents setMonth:component];
-
- if (!read2DigitNumber(&p, &component) || *p++ != 'T')
- return nil;
- [dateComponents setDay:component];
-
- if (!read2DigitNumber(&p, &component) || *p++ != ':')
- return nil;
- [dateComponents setHour:component];
-
- if (!read2DigitNumber(&p, &component) || *p++ != ':')
- return nil;
- [dateComponents setMinute:component];
-
- if (!read2DigitNumber(&p, &component) || *p++ != 'Z')
- return nil;
- [dateComponents setSecond:component];
-
-#if (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 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 < col2) ? NSOrderedAscending : ((col1 == col2) ? NSOrderedSame : NSOrderedDescending));
-}
-
-- (void)_processMetaElementWithName:(NSString *)name content:(NSString *)content {
- NSString *key = nil;
- if (NSOrderedSame == [@"CocoaVersion" compare:name options:NSCaseInsensitiveSearch]) {
- CGFloat versionNumber = [content doubleValue];
- if (versionNumber > 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 == [@"Generator" compare:name options:NSCaseInsensitiveSearch]) {
- key = NSGeneratorDocumentAttribute;
-#endif
- } else if (NSOrderedSame == [@"Keywords" compare:name options:NSCaseInsensitiveSearch]) {
- if (content && [content length] > 0) {
- NSArray *array;
- // ??? need better handling here and throughout
- if ([content rangeOfString:@", "].length == 0 && [content rangeOfString:@","].length > 0)
- array = [content componentsSeparatedByString:@","];
- else if ([content rangeOfString:@", "].length == 0 && [content rangeOfString:@" "].length > 0)
- array = [content componentsSeparatedByString:@" "];
- else
- array = [content componentsSeparatedByString:@", "];
- [_documentAttrs setObject:array forKey:NSKeywordsDocumentAttribute];
- }
- } else if (NSOrderedSame == [@"Author" compare:name options:NSCaseInsensitiveSearch])
- key = NSAuthorDocumentAttribute;
- else if (NSOrderedSame == [@"LastAuthor" compare:name options:NSCaseInsensitiveSearch])
- key = NSEditorDocumentAttribute;
- else if (NSOrderedSame == [@"Company" compare:name options:NSCaseInsensitiveSearch])
- key = NSCompanyDocumentAttribute;
- else if (NSOrderedSame == [@"Copyright" compare:name options:NSCaseInsensitiveSearch])
- key = NSCopyrightDocumentAttribute;
- else if (NSOrderedSame == [@"Subject" compare:name options:NSCaseInsensitiveSearch])
- key = NSSubjectDocumentAttribute;
- else if (NSOrderedSame == [@"Description" compare:name options:NSCaseInsensitiveSearch] || NSOrderedSame == [@"Comment" compare:name options:NSCaseInsensitiveSearch])
- key = NSCommentDocumentAttribute;
- else if (NSOrderedSame == [@"CreationTime" compare:name options:NSCaseInsensitiveSearch]) {
- if (content && [content length] > 0) {
- NSDate *date = _dateForString(content);
- if (date)
- [_documentAttrs setObject:date forKey:NSCreationTimeDocumentAttribute];
- }
- } else if (NSOrderedSame == [@"ModificationTime" compare:name options:NSCaseInsensitiveSearch]) {
- if (content && [content length] > 0) {
- NSDate *date = _dateForString(content);
- if (date)
- [_documentAttrs setObject:date forKey:NSModificationTimeDocumentAttribute];
- }
- }
-#if PLATFORM(IOS)
- else if (NSOrderedSame == [@"DisplayName" compare:name options:NSCaseInsensitiveSearch] || NSOrderedSame == [@"IndexTitle" compare:name options:NSCaseInsensitiveSearch])
- key = NSDisplayNameDocumentAttribute;
- else if (NSOrderedSame == [@"robots" compare:name options:NSCaseInsensitiveSearch]) {
- if ([content rangeOfString:@"noindex" options:NSCaseInsensitiveSearch].length > 0)
- [_documentAttrs setObject:[NSNumber numberWithInteger:1] forKey:NSNoIndexDocumentAttribute];
- }
-#endif
- if (key && content && [content length] > 0)
- [_documentAttrs setObject:content forKey:key];
-}
-
-- (void)_processHeadElement:(DOMElement *)element {
- // ??? should gather data from other sources e.g. Word, but for that we would need to be able to get comments from DOM
- NSArray *childNodes = [self _childrenForNode:element];
- NSUInteger count = [childNodes count];
- for (NSUInteger i = 0; i < count; i++) {
- DOMNode *node = [childNodes objectAtIndex:i];
- unsigned short nodeType = [node nodeType];
- if (DOM_ELEMENT_NODE == nodeType) {
- DOMElement *element = (DOMElement *)node;
- NSString *tag = [element tagName];
- if ([@"META" isEqualToString:tag] && [element respondsToSelector:@selector(name)] && [element respondsToSelector:@selector(content)]) {
- NSString *name = [(DOMHTMLMetaElement *)element name];
- NSString *content = [(DOMHTMLMetaElement *)element content];
- if (name && content)
- [self _processMetaElementWithName:name content:content];
- }
- }
- }
-}
-
-- (BOOL)_enterElement:(DOMElement *)element tag:(NSString *)tag display:(NSString *)displayVal embedded:(BOOL)embedded
-{
- if ([@"HEAD" isEqualToString:tag] && !embedded)
- [self _processHeadElement:element];
- else if (!displayVal || !([@"none" isEqualToString:displayVal] || [@"table-column" isEqualToString:displayVal] || [@"table-column-group" isEqualToString:displayVal])) {
- if ([self _elementIsBlockLevel:element] && ![@"BR" isEqualToString:tag] && !([@"table-cell" isEqualToString:displayVal] && [_textTables count] == 0)
- && !([_textLists count] > 0 && [@"block" isEqualToString:displayVal] && ![@"LI" isEqualToString:tag] && ![@"UL" isEqualToString:tag] && ![@"OL" isEqualToString:tag]))
- [self _newParagraphForElement:element tag:tag allowEmpty:NO suppressTrailingSpace:YES];
- return YES;
- }
- return NO;
-}
-
-- (void)_addTableForElement:(DOMElement *)tableElement
-{
- RetainPtr<NSTextTable> 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) {
- NSString *borderCollapse = [self _stringForNode:tableElement property:CSSPropertyBorderCollapse];
- NSString *emptyCells = [self _stringForNode:tableElement property:CSSPropertyEmptyCells];
- NSString *tableLayout = [self _stringForNode:tableElement property:CSSPropertyTableLayout];
- if ([tableElement respondsToSelector:@selector(cellSpacing)]) {
- NSString *cellSpacing = [(DOMHTMLTableElement *)tableElement cellSpacing];
- if (cellSpacing && [cellSpacing length] > 0 && ![cellSpacing hasSuffix:@"%"]) cellSpacingVal = [cellSpacing floatValue];
- }
- if ([tableElement respondsToSelector:@selector(cellPadding)]) {
- NSString *cellPadding = [(DOMHTMLTableElement *)tableElement cellPadding];
- if (cellPadding && [cellPadding length] > 0 && ![cellPadding hasSuffix:@"%"]) cellPaddingVal = [cellPadding floatValue];
- }
- [self _fillInBlock:table.get() forElement:tableElement backgroundColor:nil extraMargin:0 extraPadding:0 isTable:YES];
- if ([@"collapse" isEqualToString:borderCollapse]) {
- [table setCollapsesBorders:YES];
- cellSpacingVal = 0;
- }
- if ([@"hide" isEqualToString:emptyCells]) [table setHidesEmptyCells:YES];
- if ([@"fixed" isEqualToString:tableLayout]) [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)_addTableCellForElement:(DOMElement *)tableCellElement
-{
- 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] > 0) ? [_textTableRowBackgroundColors lastObject] : nil;
- NSTextTableBlock *previousBlock;
- CGFloat cellSpacingVal = [[_textTableSpacings lastObject] floatValue];
- if ([color isEqual:[PlatformColorClass clearColor]]) color = nil;
- for (NSUInteger i = 0; i < count; i++) {
- previousBlock = [rowArray objectAtIndex:i];
- if (columnNumber >= [previousBlock startingColumn] && columnNumber < [previousBlock startingColumn] + [previousBlock columnSpan])
- columnNumber = [previousBlock startingColumn] + [previousBlock columnSpan];
- }
- if (tableCellElement) {
- if ([tableCellElement respondsToSelector:@selector(rowSpan)]) {
- rowSpan = [(DOMHTMLTableCellElement *)tableCellElement rowSpan];
- if (rowSpan < 1)
- rowSpan = 1;
- }
- if ([tableCellElement respondsToSelector:@selector(colSpan)]) {
- colSpan = [(DOMHTMLTableCellElement *)tableCellElement colSpan];
- if (colSpan < 1)
- colSpan = 1;
- }
- }
- RetainPtr<NSTextTableBlock> block = adoptNS([[PlatformNSTextTableBlock alloc] initWithTable:table startingRow:rowNumber rowSpan:rowSpan startingColumn:columnNumber columnSpan:colSpan]);
- if (tableCellElement) {
- NSString *verticalAlign = [self _stringForNode:tableCellElement property:CSSPropertyVerticalAlign];
- [self _fillInBlock:block.get() forElement:tableCellElement backgroundColor:color extraMargin:cellSpacingVal / 2 extraPadding:0 isTable:NO];
- if ([@"middle" isEqualToString:verticalAlign])
- [block setVerticalAlignment:NSTextBlockMiddleAlignment];
- else if ([@"bottom" isEqualToString:verticalAlign])
- [block setVerticalAlignment:NSTextBlockBottomAlignment];
- else if ([@"baseline" isEqualToString:verticalAlign])
- [block setVerticalAlignment:NSTextBlockBaselineAlignment];
- else if ([@"top" isEqualToString:verticalAlign])
- [block setVerticalAlignment:NSTextBlockTopAlignment];
- }
- [_textBlocks addObject:block.get()];
- [rowArray addObject:block.get()];
- [rowArray sortUsingFunction:_colCompare context:NULL];
-}
-
-- (BOOL)_processElement:(DOMElement *)element tag:(NSString *)tag display:(NSString *)displayVal depth:(NSInteger)depth
-{
- BOOL retval = YES;
- BOOL isBlockLevel = [self _elementIsBlockLevel:element];
- if (isBlockLevel)
- [_writingDirectionArray removeAllObjects];
- else {
- NSString *bidi = [self _stringForNode:element property:CSSPropertyUnicodeBidi];
- if (bidi && [bidi isEqualToString:@"embed"]) {
- NSUInteger val = NSTextWritingDirectionEmbedding;
- NSString *direction = [self _stringForNode:element property:CSSPropertyDirection];
- if ([direction isEqualToString:@"rtl"])
- val |= NSWritingDirectionRightToLeft;
- [_writingDirectionArray addObject:[NSNumber numberWithUnsignedInteger:val]];
- } else if (bidi && [bidi isEqualToString:@"bidi-override"]) {
- NSUInteger val = NSTextWritingDirectionOverride;
- NSString *direction = [self _stringForNode:element property:CSSPropertyDirection];
- if ([direction isEqualToString:@"rtl"])
- val |= NSWritingDirectionRightToLeft;
- [_writingDirectionArray addObject:[NSNumber numberWithUnsignedInteger:val]];
- }
- }
- if ([@"table" isEqualToString:displayVal] || ([_textTables count] == 0 && [@"table-row-group" isEqualToString:displayVal])) {
- DOMElement *tableElement = element;
- if ([@"table-row-group" isEqualToString:displayVal]) {
- // If we are starting in medias res, the first thing we see may be the tbody, so go up to the table
- tableElement = [self _blockLevelElementForNode:[element parentNode]];
- if (![@"table" isEqualToString:[self _stringForNode:tableElement property:CSSPropertyDisplay]])
- tableElement = element;
- }
- while ([_textTables count] > [_textBlocks count])
- [self _addTableCellForElement:nil];
- [self _addTableForElement:tableElement];
- } else if ([@"table-footer-group" isEqualToString:displayVal] && [_textTables count] > 0) {
- [_textTableFooters setObject:element forKey:[NSValue valueWithNonretainedObject:[_textTables lastObject]]];
- retval = NO;
- } else if ([@"table-row" isEqualToString:displayVal] && [_textTables count] > 0) {
- PlatformColor *color = [self _colorForNode:element property:CSSPropertyBackgroundColor];
- if (!color) color = [PlatformColorClass clearColor];
- [_textTableRowBackgroundColors addObject:color];
- } else if ([@"table-cell" isEqualToString:displayVal]) {
- while ([_textTables count] < [_textBlocks count] + 1) {
- [self _addTableForElement:nil];
- }
- [self _addTableCellForElement:element];
- } else if ([@"IMG" isEqualToString:tag]) {
- NSString *urlString = [element getAttribute:@"src"];
- if (urlString && [urlString length] > 0) {
- NSURL *url = core([element ownerDocument])->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)
- [self _addAttachmentForElement:element URL:url needsParagraph:isBlockLevel usePlaceholder:usePlaceholderImage];
- }
- retval = NO;
- } else if ([@"OBJECT" isEqualToString:tag]) {
- NSString *baseString = [element getAttribute:@"codebase"];
- NSString *urlString = [element getAttribute:@"data"];
- NSString *declareString = [element getAttribute:@"declare"];
- if (urlString && [urlString length] > 0 && ![@"true" isEqualToString:declareString]) {
- NSURL *baseURL = nil;
- NSURL *url = nil;
- if (baseString && [baseString length] > 0) {
- baseURL = core([element ownerDocument])->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 =core([element ownerDocument])->completeURL(stripLeadingAndTrailingHTMLSpaces(urlString));
- if (!url)
- url = [NSURL _web_URLWithString:[urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] relativeToURL:_baseURL];
- if (url)
- retval = ![self _addAttachmentForElement:element URL:url needsParagraph:isBlockLevel usePlaceholder:NO];
- }
- } else if ([@"FRAME" isEqualToString:tag]) {
- if ([element respondsToSelector:@selector(contentDocument)]) {
- DOMDocument *contentDocument = [(DOMHTMLFrameElement *)element contentDocument];
- if (contentDocument)
- [self _traverseNode:contentDocument depth:depth + 1 embedded:YES];
- }
- retval = NO;
- } else if ([@"IFRAME" isEqualToString:tag]) {
- if ([element respondsToSelector:@selector(contentDocument)]) {
- DOMDocument *contentDocument = [(DOMHTMLIFrameElement *)element contentDocument];
- if (contentDocument) {
- [self _traverseNode:contentDocument depth:depth + 1 embedded:YES];
- retval = NO;
- }
- }
- } else if ([@"BR" isEqualToString:tag]) {
- DOMElement *blockElement = [self _blockLevelElementForNode:[element parentNode]];
- NSString *breakClass = [element getAttribute:@"class"], *blockTag = [blockElement tagName];
- BOOL isExtraBreak = [@"Apple-interchange-newline" isEqualToString:breakClass], blockElementIsParagraph = ([@"P" isEqualToString:blockTag] || [@"LI" isEqualToString:blockTag] || ([blockTag hasPrefix:@"H"] && 2 == [blockTag length]));
- if (isExtraBreak)
- _flags.hasTrailingNewline = YES;
- else {
- if (blockElement && blockElementIsParagraph)
- [self _newLineForElement:element];
- else
- [self _newParagraphForElement:element tag:tag allowEmpty:YES suppressTrailingSpace:NO];
- }
- } else if ([@"UL" isEqualToString:tag]) {
- RetainPtr<NSTextList> list;
- NSString *listStyleType = [self _stringForNode:element property:CSSPropertyListStyleType];
- if (!listStyleType || [listStyleType length] == 0)
- listStyleType = @"disc";
- list = adoptNS([[PlatformNSTextList alloc] initWithMarkerFormat:[NSString stringWithFormat:@"{%@}", listStyleType] options:0]);
- [_textLists addObject:list.get()];
- } else if ([@"OL" isEqualToString:tag]) {
- RetainPtr<NSTextList> list;
- NSString *listStyleType = [self _stringForNode:element property:CSSPropertyListStyleType];
- if (!listStyleType || [listStyleType length] == 0) listStyleType = @"decimal";
- list = adoptNS([[PlatformNSTextList alloc] initWithMarkerFormat:[NSString stringWithFormat:@"{%@}.", listStyleType] options:0]);
- if ([element respondsToSelector:@selector(start)]) {
- NSInteger startingItemNumber = [(DOMHTMLOListElement *)element start];
- [list setStartingItemNumber:startingItemNumber];
- }
- [_textLists addObject:list.get()];
- } else if ([@"Q" isEqualToString:tag]) {
- [self _addQuoteForElement:element opening:YES level:_quoteLevel++];
- } else if ([@"INPUT" isEqualToString:tag]) {
- if ([element respondsToSelector:@selector(type)] && [element respondsToSelector:@selector(value)] && [@"text" compare:[(DOMHTMLInputElement *)element type] options:NSCaseInsensitiveSearch] == NSOrderedSame) {
- NSString *value = [(DOMHTMLInputElement *)element value];
- if (value && [value length] > 0) [self _addValue:value forElement:element];
- }
- } else if ([@"TEXTAREA" isEqualToString:tag]) {
- if ([element respondsToSelector:@selector(value)]) {
- NSString *value = [(DOMHTMLTextAreaElement *)element value];
- if (value && [value length] > 0) [self _addValue:value forElement:element];
- }
- retval = NO;
- }
- return retval;
-}
-
-- (void)_addMarkersToList:(NSTextList *)list range:(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 >= textLength)
- return;
- if (NSMaxRange(range) > 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 && listIndex != NSNotFound) {
- for (NSUInteger idx = range.location; idx < NSMaxRange(range);) {
- paragraphRange = [string paragraphRangeForRange:NSMakeRange(idx, 0)];
- paragraphStyle = [_attrStr attribute:NSParagraphStyleAttributeName atIndex:idx effectiveRange:&styleRange];
- font = [_attrStr attribute:NSFontAttributeName atIndex:idx effectiveRange:NULL];
- pointSize = font ? [font pointSize] : 12;
- if ([[paragraphStyle textLists] count] == listIndex + 1) {
- stringToInsert = [NSString stringWithFormat:@"\t%@\t", [list markerForItemNumber:itemNum++]];
- insertLength = [stringToInsert length];
- if (!_flags.isIndexing && !_flags.isTesting)
- attrsToInsert = [PlatformNSTextList _standardMarkerAttributesForAttributes:[_attrStr attributesAtIndex:paragraphRange.location effectiveRange:NULL]];
-
- [_attrStr replaceCharactersInRange:NSMakeRange(paragraphRange.location, 0) withString:stringToInsert];
- if (!_flags.isIndexing && !_flags.isTesting) [_attrStr setAttributes:attrsToInsert range:NSMakeRange(paragraphRange.location, insertLength)];
- range.length += insertLength;
- paragraphRange.length += insertLength;
- if (paragraphRange.location < _domRangeStartIndex) _domRangeStartIndex += insertLength;
-
- newStyle = [paragraphStyle mutableCopy];
- listLocation = (listIndex + 1) * 36;
- markerLocation = listLocation - 25;
- [newStyle setFirstLineHeadIndent:0];
- [newStyle setHeadIndent:listLocation];
- while ((count = [[newStyle tabStops] count]) > 0) {
- for (i = 0, tabToRemove = nil; !tabToRemove && i < count; i++) {
- tab = [[newStyle tabStops] objectAtIndex:i];
- if ([tab location] <= 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];
- if (!_flags.isIndexing && !_flags.isTesting) [_attrStr addAttribute:NSParagraphStyleAttributeName value:newStyle range:paragraphRange];
- [newStyle release];
-
- idx = NSMaxRange(paragraphRange);
- } else {
- // skip any deeper-nested lists
- idx = NSMaxRange(styleRange);
- }
- }
- }
- }
-}
-
-- (void)_exitElement:(DOMElement *)element tag:(NSString *)tag display:(NSString *)displayVal depth:(NSInteger)depth startIndex:(NSUInteger)startIndex
-{
- NSRange range = NSMakeRange(startIndex, [_attrStr length] - startIndex);
- if (range.length > 0 && [@"A" isEqualToString:tag]) {
- NSString *urlString = [element getAttribute:@"href"];
- NSString *strippedString = [urlString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
- if (urlString && [urlString length] > 0 && strippedString && [strippedString length] > 0 && ![strippedString hasPrefix:@"#"]) {
- NSURL *url = core([element ownerDocument])->completeURL(stripLeadingAndTrailingHTMLSpaces(urlString));
- if (!url)
- url = core([element ownerDocument])->completeURL(stripLeadingAndTrailingHTMLSpaces(strippedString));
- if (!url)
- url = [NSURL _web_URLWithString:strippedString relativeToURL:_baseURL];
- if (!_flags.isIndexing && !_flags.isTesting)
- [_attrStr addAttribute:NSLinkAttributeName value:url ? (id)url : (id)urlString range:range];
- }
- }
- if (!_flags.reachedEnd && [self _elementIsBlockLevel:element]) {
- [_writingDirectionArray removeAllObjects];
- if ([@"table-cell" isEqualToString:displayVal] && [_textBlocks count] == 0) {
- [self _newTabForElement:element];
- } else if ([_textLists count] > 0 && [@"block" isEqualToString:displayVal] && ![@"LI" isEqualToString:tag] && ![@"UL" isEqualToString:tag] && ![@"OL" isEqualToString:tag]) {
- [self _newLineForElement:element];
- } else {
- [self _newParagraphForElement:element tag:tag allowEmpty:(range.length == 0) suppressTrailingSpace:YES];
- }
- } else if ([_writingDirectionArray count] > 0) {
- NSString *bidi = [self _stringForNode:element property:CSSPropertyUnicodeBidi];
- if (bidi && ([bidi isEqualToString:@"embed"] || [bidi isEqualToString:@"bidi-override"])) {
- [_writingDirectionArray removeLastObject];
- }
- }
- range = NSMakeRange(startIndex, [_attrStr length] - startIndex);
- if ([@"table" isEqualToString:displayVal] && [_textTables count] > 0) {
- NSValue *key = [NSValue valueWithNonretainedObject:[_textTables lastObject]];
- DOMNode *footer = [_textTableFooters objectForKey:key];
- while ([_textTables count] < [_textBlocks count] + 1)
- [_textBlocks removeLastObject];
- if (footer) {
- [self _traverseFooterNode:footer depth:depth + 1];
- [_textTableFooters removeObjectForKey:key];
- }
- [_textTables removeLastObject];
- [_textTableSpacings removeLastObject];
- [_textTablePaddings removeLastObject];
- [_textTableRows removeLastObject];
- [_textTableRowArrays removeLastObject];
- } else if ([@"table-row" isEqualToString:displayVal] && [_textTables count] > 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 < count; i++) {
- block = [previousRowArray objectAtIndex:i];
- if ([block startingColumn] + [block columnSpan] > numberOfColumns) numberOfColumns = [block startingColumn] + [block columnSpan];
- if ([block startingRow] + [block rowSpan] > rowNumber) [rowArray addObject:block];
- }
- count = [rowArray count];
- openColumn = 0;
- for (i = 0; i < count; i++) {
- block = [rowArray objectAtIndex:i];
- if (openColumn >= [block startingColumn] && openColumn < [block startingColumn] + [block columnSpan]) openColumn = [block startingColumn] + [block columnSpan];
- }
- } while (openColumn >= numberOfColumns);
- if ((NSUInteger)numberOfColumns > [table numberOfColumns])
- [table setNumberOfColumns:numberOfColumns];
- [_textTableRows removeLastObject];
- [_textTableRows addObject:[NSNumber numberWithInteger:rowNumber]];
- [_textTableRowArrays removeLastObject];
- [_textTableRowArrays addObject:rowArray];
- if ([_textTableRowBackgroundColors count] > 0)
- [_textTableRowBackgroundColors removeLastObject];
- } else if ([@"table-cell" isEqualToString:displayVal] && [_textBlocks count] > 0) {
- while ([_textTables count] > [_textBlocks count]) {
- [_textTables removeLastObject];
- [_textTableSpacings removeLastObject];
- [_textTablePaddings removeLastObject];
- [_textTableRows removeLastObject];
- [_textTableRowArrays removeLastObject];
- }
- [_textBlocks removeLastObject];
- } else if (([@"UL" isEqualToString:tag] || [@"OL" isEqualToString:tag]) && [_textLists count] > 0) {
- NSTextList *list = [_textLists lastObject];
- [self _addMarkersToList:list range:range];
- [_textLists removeLastObject];
- } else if ([@"Q" isEqualToString:tag]) {
- [self _addQuoteForElement:element opening:NO level:--_quoteLevel];
- } else if ([@"SPAN" isEqualToString:tag]) {
- NSString *className = [element getAttribute:@"class"];
- NSMutableString *mutableString;
- NSUInteger i, count = 0;
- unichar c;
- if ([@"Apple-converted-space" isEqualToString:className]) {
- mutableString = [_attrStr mutableString];
- for (i = range.location; i < NSMaxRange(range); i++) {
- c = [mutableString characterAtIndex:i];
- if (0xa0 == c)
- [mutableString replaceCharactersInRange:NSMakeRange(i, 1) withString:@" "];
- }
- } else if ([@"Apple-converted-tab" isEqualToString:className]) {
- mutableString = [_attrStr mutableString];
- for (i = range.location; i < NSMaxRange(range); i++) {
- NSRange rangeToReplace = NSMakeRange(NSNotFound, 0);
- c = [mutableString characterAtIndex:i];
- if (' ' == c || 0xa0 == c) {
- count++;
- if (count >= 4 || i + 1 >= NSMaxRange(range))
- rangeToReplace = NSMakeRange(i + 1 - count, count);
- } else {
- if (count > 0)
- rangeToReplace = NSMakeRange(i - count, count);
- }
- if (rangeToReplace.length > 0) {
- [mutableString replaceCharactersInRange:rangeToReplace withString:@"\t"];
- range.length -= (rangeToReplace.length - 1);
- i -= (rangeToReplace.length - 1);
- if (NSMaxRange(rangeToReplace) <= _domRangeStartIndex) {
- _domRangeStartIndex -= (rangeToReplace.length - 1);
- } else if (rangeToReplace.location < _domRangeStartIndex) {
- _domRangeStartIndex = rangeToReplace.location;
- }
- count = 0;
- }
- }
- }
- }
-}
-
-- (void)_processText:(DOMCharacterData *)text
-{
- NSString *instr = [text data];
- NSString *outstr = instr;
- NSString *whitespaceVal;
- NSString *transformVal;
- NSUInteger textLength = [_attrStr length];
- NSUInteger startOffset = 0;
- NSUInteger endOffset = [instr length];
- unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : '\n';
- BOOL wasSpace = NO;
- BOOL wasLeading = YES;
- BOOL suppressLeadingSpace = ((_flags.isSoft && lastChar == ' ') || lastChar == '\n' || lastChar == '\r' || lastChar == '\t' || lastChar == NSParagraphSeparatorCharacter || lastChar == NSLineSeparatorCharacter || lastChar == NSFormFeedCharacter || lastChar == WebNextLineCharacter);
- NSRange rangeToReplace = NSMakeRange(textLength, 0);
- CFMutableStringRef mutstr = NULL;
- whitespaceVal = [self _stringForNode:text property:CSSPropertyWhiteSpace];
- transformVal = [self _stringForNode:text property:CSSPropertyTextTransform];
-
- if (_domRange) {
- if (text == [_domRange startContainer]) {
- startOffset = (NSUInteger)[_domRange startOffset];
- _domRangeStartIndex = [_attrStr length];
- _flags.reachedStart = YES;
- }
- if (text == [_domRange endContainer]) {
- endOffset = (NSUInteger)[_domRange endOffset];
- _flags.reachedEnd = YES;
- }
- if ((startOffset > 0 || endOffset < [instr length]) && endOffset >= startOffset) {
- instr = [instr substringWithRange:NSMakeRange(startOffset, endOffset - startOffset)];
- outstr = instr;
- }
- }
- if ([whitespaceVal hasPrefix:@"pre"]) {
- if (textLength > 0 && [instr length] > 0 && _flags.isSoft) {
- unichar c = [instr characterAtIndex:0];
- if (c == '\n' || c == '\r' || c == NSParagraphSeparatorCharacter || c == NSLineSeparatorCharacter || c == NSFormFeedCharacter || c == WebNextLineCharacter)
- rangeToReplace = NSMakeRange(textLength - 1, 1);
- }
- } else {
- CFStringInlineBuffer inlineBuffer;
- const unsigned int TextBufferSize = 255;
-
- unichar buffer[TextBufferSize + 1];
- NSUInteger i, count = [instr length], idx = 0;
-
- mutstr = CFStringCreateMutable(NULL, 0);
- CFStringInitInlineBuffer((CFStringRef)instr, &inlineBuffer, CFRangeMake(0, count));
- for (i = 0; i < count; i++) {
- unichar c = CFStringGetCharacterFromInlineBuffer(&inlineBuffer, i);
- if (c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == 0xc || c == 0x200b) {
- wasSpace = (!wasLeading || !suppressLeadingSpace);
- } else {
- if (wasSpace)
- buffer[idx++] = ' ';
- buffer[idx++] = c;
- if (idx >= TextBufferSize) {
- CFStringAppendCharacters(mutstr, buffer, idx);
- idx = 0;
- }
- wasSpace = wasLeading = NO;
- }
- }
- if (wasSpace)
- buffer[idx++] = ' ';
- if (idx > 0)
- CFStringAppendCharacters(mutstr, buffer, idx);
- outstr = (NSString *)mutstr;
- }
- if ([outstr length] > 0) {
- if ([@"capitalize" isEqualToString:transformVal])
- outstr = [outstr capitalizedString];
- else if ([@"uppercase" isEqualToString:transformVal])
- outstr = [outstr uppercaseString];
- else if ([@"lowercase" isEqualToString:transformVal])
- outstr = [outstr lowercaseString];
- [_attrStr replaceCharactersInRange:rangeToReplace withString:outstr];
- rangeToReplace.length = [outstr length];
- if (!_flags.isIndexing) {
- RetainPtr<NSDictionary> attrs;
- DOMElement *element = (DOMElement *)text;
- while (element) {
- // Fill attrs dictionary with attributes from parent nodes, not overwriting ones deeper in the tree
- if([element nodeType] == DOM_ELEMENT_NODE) {
- RetainPtr<NSMutableDictionary> newAttrs = adoptNS([[self _attributesForElement:element] mutableCopy]);
- if (attrs) {
- // Already-set attributes (from lower in the tree) overwrite the higher ones.
- [newAttrs addEntriesFromDictionary:attrs.get()];
- }
- attrs = newAttrs;
- }
- element = (DOMElement *)[element parentNode];
- }
- if (!_flags.isTesting && rangeToReplace.length > 0)
- [_attrStr setAttributes:attrs.get() range:rangeToReplace];
- }
- _flags.isSoft = wasSpace;
- }
- if (mutstr)
- CFRelease(mutstr);
-}
-
-- (void)_traverseNode:(DOMNode *)node depth:(NSInteger)depth embedded:(BOOL)embedded
-{
- unsigned short nodeType;
- NSArray *childNodes;
- NSUInteger count;
- NSUInteger startOffset;
- NSUInteger endOffset;
- BOOL isStart = NO;
- BOOL isEnd = NO;
-
- if (_flags.reachedEnd)
- return;
- if (_domRange && !_flags.reachedStart && _domStartAncestors && ![_domStartAncestors containsObject:node])
- return;
-
- nodeType = [node nodeType];
- childNodes = [self _childrenForNode:node];
- count = [childNodes count];
- startOffset = 0;
- endOffset = count;
-
- if (_domRange) {
- if (node == [_domRange startContainer]) {
- startOffset = (NSUInteger)[_domRange startOffset];
- isStart = YES;
- _flags.reachedStart = YES;
- }
- if (node == [_domRange endContainer]) {
- endOffset = (NSUInteger)[_domRange endOffset];
- isEnd = YES;
- }
- }
-
- if (nodeType == DOM_DOCUMENT_NODE || nodeType == DOM_DOCUMENT_FRAGMENT_NODE) {
- for (NSUInteger i = 0; i < count; i++) {
- if (isStart && i == startOffset)
- _domRangeStartIndex = [_attrStr length];
- if ((!isStart || startOffset <= i) && (!isEnd || endOffset > i))
- [self _traverseNode:[childNodes objectAtIndex:i] depth:depth + 1 embedded:embedded];
- if (isEnd && i + 1 >= endOffset)
- _flags.reachedEnd = YES;
- if (_thumbnailLimit > 0 && [_attrStr length] >= _thumbnailLimit)
- _flags.reachedEnd = YES;
- if (_flags.reachedEnd) break;
- }
- } else if (nodeType == DOM_ELEMENT_NODE) {
- DOMElement *element = (DOMElement *)node;
- NSString *tag = [element tagName], *displayVal = [self _stringForNode:element property:CSSPropertyDisplay];
- if ([self _enterElement:element tag:tag display:displayVal embedded:embedded]) {
- NSUInteger startIndex = [_attrStr length];
- if ([self _processElement:element tag:tag display:displayVal depth:depth]) {
- for (NSUInteger i = 0; i < count; i++) {
- if (isStart && i == startOffset)
- _domRangeStartIndex = [_attrStr length];
- if ((!isStart || startOffset <= i) && (!isEnd || endOffset > i))
- [self _traverseNode:[childNodes objectAtIndex:i] depth:depth + 1 embedded:embedded];
- if (isEnd && i + 1 >= endOffset)
- _flags.reachedEnd = YES;
- if (_flags.reachedEnd)
- break;
- }
- [self _exitElement:element tag:tag display:displayVal depth:depth startIndex:startIndex];
- }
- }
- } else if (nodeType == DOM_TEXT_NODE || nodeType == DOM_CDATA_SECTION_NODE) {
- [self _processText:(DOMCharacterData *)node];
- }
-
- if (isEnd) _flags.reachedEnd = YES;
-}
-
-- (void)_traverseFooterNode:(DOMNode *)node depth:(NSInteger)depth
-{
- DOMElement *element = (DOMElement *)node;
- NSArray *childNodes = [self _childrenForNode:node];
- NSString *tag = @"TBODY", *displayVal = @"table-row-group";
- NSUInteger count = [childNodes count];
- NSUInteger startOffset = 0;
- NSUInteger endOffset = count;
- BOOL isStart = NO;
- BOOL isEnd = NO;
-
- if (_flags.reachedEnd)
- return;
- if (_domRange && !_flags.reachedStart && _domStartAncestors && ![_domStartAncestors containsObject:node])
- return;
- if (_domRange) {
- if (node == [_domRange startContainer]) {
- startOffset = (NSUInteger)[_domRange startOffset];
- isStart = YES;
- _flags.reachedStart = YES;
- }
- if (node == [_domRange endContainer]) {
- endOffset = (NSUInteger)[_domRange endOffset];
- isEnd = YES;
- }
- }
- if ([self _enterElement:element tag:tag display:displayVal embedded:YES]) {
- NSUInteger startIndex = [_attrStr length];
- if ([self _processElement:element tag:tag display:displayVal depth:depth]) {
- for (NSUInteger i = 0; i < count; i++) {
- if (isStart && i == startOffset)
- _domRangeStartIndex = [_attrStr length];
- if ((!isStart || startOffset <= i) && (!isEnd || endOffset > i))
- [self _traverseNode:[childNodes objectAtIndex:i] depth:depth + 1 embedded:YES];
- if (isEnd && i + 1 >= endOffset)
- _flags.reachedEnd = YES;
- if (_flags.reachedEnd)
- break;
- }
- [self _exitElement:element tag:tag display:displayVal depth:depth startIndex:startIndex];
- }
- }
- if (isEnd)
- _flags.reachedEnd = YES;
-}
-
-- (void)_adjustTrailingNewline
-{
- NSUInteger textLength = [_attrStr length];
- unichar lastChar = (textLength > 0) ? [[_attrStr string] characterAtIndex:textLength - 1] : 0;
- BOOL alreadyHasTrailingNewline = (lastChar == '\n' || lastChar == '\r' || lastChar == NSParagraphSeparatorCharacter || lastChar == NSLineSeparatorCharacter || lastChar == WebNextLineCharacter);
- if (_flags.hasTrailingNewline && !alreadyHasTrailingNewline)
- [_attrStr replaceCharactersInRange:NSMakeRange(textLength, 0) withString:@"\n"];
-}
-
-- (void)_loadFromDOMRange
-{
- if (-1 == _errorCode) {
- DOMNode *commonAncestorContainer = [_domRange commonAncestorContainer];
- DOMNode *ancestorContainer = [_domRange startContainer];
-
- _domStartAncestors = [[NSMutableArray alloc] init];
- while (ancestorContainer) {
- [_domStartAncestors addObject:ancestorContainer];
- if (ancestorContainer == commonAncestorContainer)
- break;
- ancestorContainer = [ancestorContainer parentNode];
- }
- _document = [commonAncestorContainer ownerDocument];
- _dataSource = (DocumentLoader *)core(_document)->frame()->loader().documentLoader();
- if (_textSizeMultiplier <= 0.0)
- _textSizeMultiplier = 1;
- if (_defaultFontSize <= 0.0)
- _defaultFontSize = 12;
- if (_minimumFontSize < 1.0)
- _minimumFontSize = 1;
- if (_document && _dataSource) {
- _domRangeStartIndex = 0;
- _errorCode = 0;
- [self _traverseNode:commonAncestorContainer depth:0 embedded:NO];
- if (_domRangeStartIndex > 0 && _domRangeStartIndex <= [_attrStr length])
- [_attrStr deleteCharactersInRange:NSMakeRange(0, _domRangeStartIndex)];
- }
- }
-}
-
-- (void)dealloc
-{
- [_attrStr release];
- [_documentAttrs release];
- [_domRange release];
- [_domStartAncestors release];
- [_standardFontFamily release];
- [_textLists release];
- [_textBlocks release];
- [_textTables release];
- [_textTableFooters release];
- [_textTableSpacings release];
- [_textTablePaddings release];
- [_textTableRows release];
- [_textTableRowArrays release];
- [_textTableRowBackgroundColors release];
- [_attributesForElements release];
- [_fontCache release];
- [_writingDirectionArray release];
- [super dealloc];
-}
-
-- (id)init
-{
- self = [super init];
- if (!self)
- return nil;
-
- _attrStr = [[NSMutableAttributedString alloc] init];
- _documentAttrs = [[NSMutableDictionary alloc] init];
-
- _textLists = [[NSMutableArray alloc] init];
- _textBlocks = [[NSMutableArray alloc] init];
- _textTables = [[NSMutableArray alloc] init];
- _textTableFooters = [[NSMutableDictionary alloc] init];
- _textTableSpacings = [[NSMutableArray alloc] init];
- _textTablePaddings = [[NSMutableArray alloc] init];
- _textTableRows = [[NSMutableArray alloc] init];
- _textTableRowArrays = [[NSMutableArray alloc] init];
- _textTableRowBackgroundColors = [[NSMutableArray alloc] init];
- _attributesForElements = [[NSMutableDictionary alloc] init];
- _fontCache = [[NSMutableDictionary alloc] init];
- _writingDirectionArray = [[NSMutableArray alloc] init];
-
- _textSizeMultiplier = 1;
- _webViewTextSizeMultiplier = 0;
- _defaultTabInterval = 36;
- _defaultFontSize = 12;
- _minimumFontSize = 1;
- _errorCode = -1;
- _indexingLimit = 0;
- _thumbnailLimit = 0;
-
- _caches = std::make_unique<HTMLConverterCaches>();
-
- _flags.isIndexing = (_indexingLimit > 0);
- _flags.isTesting = 0;
-
- return self;
-}
-
-- (id)initWithDOMRange:(DOMRange *)domRange
-{
- self = [self init];
- if (!self)
- return nil;
- _domRange = [domRange retain];
- return self;
-}
-
-- (NSAttributedString *)attributedString
-{
- [self _loadFromDOMRange];
- return (!_errorCode) ? [[_attrStr retain] autorelease] : nil;
-}
-
-
-// This function supports more HTML features than the editing variant below, such as tables.
-+ (NSAttributedString *)attributedStringFromRange:(Range*)range
-{
- RetainPtr<WebHTMLConverter> converter = adoptNS([[WebHTMLConverter alloc] initWithDOMRange:kit(range)]);
- return [converter attributedString];
-}
-
-#if !PLATFORM(IOS)
-
-// This function uses TextIterator, which makes offsets in its result compatible with HTML editing.
-+ (NSAttributedString *)editingAttributedStringFromRange:(Range*)range
-{
- NSFontManager *fontManager = [NSFontManager sharedFontManager];
- NSMutableAttributedString *string = [[NSMutableAttributedString alloc] init];
- NSUInteger stringLength = 0;
- RetainPtr<NSMutableDictionary> attrs = adoptNS([[NSMutableDictionary alloc] init]);
-
- for (TextIterator it(range); !it.atEnd(); it.advance()) {
- RefPtr<Range> currentTextRange = it.range();
- Node* startContainer = currentTextRange->startContainer();
- Node* endContainer = currentTextRange->endContainer();
- int startOffset = currentTextRange->startOffset();
- int endOffset = currentTextRange->endOffset();
-
- if (startContainer == endContainer && (startOffset == endOffset - 1)) {
- Node* node = startContainer->childNode(startOffset);
- if (node && node->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->renderer();
- ASSERT(renderer);
- if (!renderer)
- continue;
- const RenderStyle& style = renderer->style();
- if (style.textDecorationsInEffect() & TextDecorationUnderline)
- [attrs.get() setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSUnderlineStyleAttributeName];
- if (style.textDecorationsInEffect() & TextDecorationLineThrough)
- [attrs.get() setObject:[NSNumber numberWithInteger:NSUnderlineStyleSingle] forKey:NSStrikethroughStyleAttributeName];
- if (NSFont *font = style.font().primaryFont()->getNSFont())
- [attrs.get() setObject:font forKey:NSFontAttributeName];
- else
- [attrs.get() setObject:[fontManager convertFont:WebDefaultFont() toSize:style.font().primaryFont()->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
-
-@end
-
-#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<ArchiveResource> resource = dataSource->subresource(URL);
- if (resource) {
- NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:resource->data()->createNSData().get()] autorelease];
- NSString *filename = resource->response().suggestedFilename();
- if (!filename || ![filename length])
- filename = suggestedFilenameWithMIMEType(resource->url(), resource->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& attr = element->getAttribute(srcAttr);
- if (!attr.isEmpty()) {
- NSURL *URL = element->document().completeURL(attr);
- if (DocumentLoader* loader = element->document().loader())
- wrapper = fileWrapperForURL(loader, URL);
- }
- if (!wrapper) {
- RenderImage* renderer = toRenderImage(element->renderer());
- if (renderer->cachedImage() && !renderer->cachedImage()->errorOccurred()) {
- wrapper = [[NSFileWrapper alloc] initRegularFileWithContents:(NSData *)(renderer->cachedImage()->imageForRenderer(renderer)->getTIFFRepresentation())];
- [wrapper setPreferredFilename:@"image.tiff"];
- [wrapper autorelease];
- }
- }
-
- return wrapper;
-}
-
-#endif
-
-namespace WebCore {
-
-NSAttributedString *attributedStringFromRange(Range& range)
-{
- return [WebHTMLConverter attributedStringFromRange:&range];
-}
-
-#if !PLATFORM(IOS)
-NSAttributedString *editingAttributedStringFromRange(Range& range)
-{
- return [WebHTMLConverter editingAttributedStringFromRange:&range];
-}
-#endif
-
-}
</del></span></pre>
</div>
</div>
</body>
</html>