<!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>[42372] trunk</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/42372">42372</a></dd>
<dt>Author</dt> <dd>darin@apple.com</dd>
<dt>Date</dt> <dd>2009-04-09 15:40:05 -0700 (Thu, 09 Apr 2009)</dd>
</dl>

<h3>Log Message</h3>
<pre>WebCore:

2009-04-09  Darin Adler  &lt;darin@apple.com&gt;

        Reviewed by Anders Carlsson and Sam Weinig.

        Part of &lt;rdar://problem/5438063&gt; Saving history containing 100,000 entries causes pauses of 2s while browsing

        Longer term solution is to change the design so Safari doesn't read and write all of history.
        This patch is step one: Do the serializing, which is done on the main thread, much faster.

        * WebCore.base.exp: Added new entry points.
        * WebCore.xcodeproj/project.pbxproj: Added new source files.

        * history/cf: Added.

        * history/cf/HistoryPropertyList.cpp: Added.
        * history/cf/HistoryPropertyList.h: Added. Code to write history files. In the future we'll also
        have code for reading here too.

        * platform/cf/BinaryPropertyList.cpp: Added.
        * platform/cf/BinaryPropertyList.h: Added. Code to write binary property list files.

WebKit/mac:

2009-04-09  Darin Adler  &lt;darin@apple.com&gt;

        Reviewed by Anders Carlsson and Sam Weinig.

        Part of &lt;rdar://problem/5438063&gt; Saving history containing 100,000 entries causes pauses of 2s while browsing

        Longer term solution is to change the design so Safari doesn't read and write all of history.
        This patch is step one: Do the serializing, which is done on the main thread, much faster.

        * History/WebHistory.mm:
        (-[WebHistoryPrivate data]): Added. Returns the NSData object containing serialized history.
        For creating new SPI so you can get the data in memory instead of on disk. Uses WebHistoryWriter.
        (-[WebHistoryPrivate saveToURL:error:]): Changed to call [self data
        (-[WebHistory _data]): Added.
        (WebHistoryWriter::WebHistoryWriter): Added.
        (WebHistoryWriter::writeHistoryItems): Added.

        * History/WebHistoryPrivate.h: Added a new _data method.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkWebCoreChangeLog">trunk/WebCore/ChangeLog</a></li>
<li><a href="#trunkWebCoreWebCorebaseexp">trunk/WebCore/WebCore.base.exp</a></li>
<li><a href="#trunkWebCoreWebCorexcodeprojprojectpbxproj">trunk/WebCore/WebCore.xcodeproj/project.pbxproj</a></li>
<li><a href="#trunkWebKitmacChangeLog">trunk/WebKit/mac/ChangeLog</a></li>
<li><a href="#trunkWebKitmacHistoryWebHistorymm">trunk/WebKit/mac/History/WebHistory.mm</a></li>
<li><a href="#trunkWebKitmacHistoryWebHistoryPrivateh">trunk/WebKit/mac/History/WebHistoryPrivate.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li>trunk/WebCore/history/cf/</li>
<li><a href="#trunkWebCorehistorycfHistoryPropertyListcpp">trunk/WebCore/history/cf/HistoryPropertyList.cpp</a></li>
<li><a href="#trunkWebCorehistorycfHistoryPropertyListh">trunk/WebCore/history/cf/HistoryPropertyList.h</a></li>
<li><a href="#trunkWebCoreplatformcfBinaryPropertyListcpp">trunk/WebCore/platform/cf/BinaryPropertyList.cpp</a></li>
<li><a href="#trunkWebCoreplatformcfBinaryPropertyListh">trunk/WebCore/platform/cf/BinaryPropertyList.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/ChangeLog (42371 => 42372)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/ChangeLog        2009-04-09 22:25:29 UTC (rev 42371)
+++ trunk/WebCore/ChangeLog        2009-04-09 22:40:05 UTC (rev 42372)
</span><span class="lines">@@ -1,3 +1,24 @@
</span><ins>+2009-04-09  Darin Adler  &lt;darin@apple.com&gt;
+
+        Reviewed by Anders Carlsson and Sam Weinig.
+
+        Part of &lt;rdar://problem/5438063&gt; Saving history containing 100,000 entries causes pauses of 2s while browsing
+
+        Longer term solution is to change the design so Safari doesn't read and write all of history.
+        This patch is step one: Do the serializing, which is done on the main thread, much faster.
+
+        * WebCore.base.exp: Added new entry points.
+        * WebCore.xcodeproj/project.pbxproj: Added new source files.
+
+        * history/cf: Added.
+
+        * history/cf/HistoryPropertyList.cpp: Added.
+        * history/cf/HistoryPropertyList.h: Added. Code to write history files. In the future we'll also
+        have code for reading here too.
+
+        * platform/cf/BinaryPropertyList.cpp: Added.
+        * platform/cf/BinaryPropertyList.h: Added. Code to write binary property list files.
+
</ins><span class="cx"> 2009-04-09  Simon Fraser  &lt;simon.fraser@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Reviewed by Antti Koivisto
</span></span></pre></div>
<a id="trunkWebCoreWebCorebaseexp"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/WebCore.base.exp (42371 => 42372)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/WebCore.base.exp        2009-04-09 22:25:29 UTC (rev 42371)
+++ trunk/WebCore/WebCore.base.exp        2009-04-09 22:40:05 UTC (rev 42372)
</span><span class="lines">@@ -426,6 +426,7 @@
</span><span class="cx"> __ZN7WebCore23ApplicationCacheStorage5emptyEv
</span><span class="cx"> __ZN7WebCore23ReplaceSelectionCommandC1EPNS_8DocumentEN3WTF10PassRefPtrINS_16DocumentFragmentEEEbbbbbNS_10EditActionE
</span><span class="cx"> __ZN7WebCore23createFragmentFromNodesEPNS_8DocumentERKN3WTF6VectorIPNS_4NodeELm0EEE
</span><ins>+__ZN7WebCore24BinaryPropertyListWriter17writePropertyListEv
</ins><span class="cx"> __ZN7WebCore24createFragmentFromMarkupEPNS_8DocumentERKNS_6StringES4_
</span><span class="cx"> __ZN7WebCore24decodeURLEscapeSequencesERKNS_6StringE
</span><span class="cx"> __ZN7WebCore24notifyHistoryItemChangedE
</span><span class="lines">@@ -572,7 +573,6 @@
</span><span class="cx"> __ZN7WebCore7Console21shouldPrintExceptionsEv
</span><span class="cx"> __ZN7WebCore7Console24setShouldPrintExceptionsEb
</span><span class="cx"> __ZN7WebCore7IntSizeC1ERK7_NSSize
</span><del>-__ZNK7WebCore7IntSizecv7_NSSizeEv
</del><span class="cx"> __ZN7WebCore7cookiesEPKNS_8DocumentERKNS_4KURLE
</span><span class="cx"> __ZN7WebCore7nsColorERKNS_5ColorE
</span><span class="cx"> __ZN7WebCore8Document11createRangeEv
</span><span class="lines">@@ -898,6 +898,7 @@
</span><span class="cx"> __ZNK7WebCore7CString6lengthEv
</span><span class="cx"> __ZNK7WebCore7Element12getAttributeERKNS_13QualifiedNameE
</span><span class="cx"> __ZNK7WebCore7IntRectcv7_NSRectEv
</span><ins>+__ZNK7WebCore7IntSizecv7_NSSizeEv
</ins><span class="cx"> __ZNK7WebCore8Document11completeURLERKNS_6StringE
</span><span class="cx"> __ZNK7WebCore8Document13axObjectCacheEv
</span><span class="cx"> __ZNK7WebCore8Document20cacheDocumentElementEv
</span><span class="lines">@@ -968,3 +969,9 @@
</span><span class="cx"> _wkSignalCFReadStreamEnd
</span><span class="cx"> _wkSignalCFReadStreamError
</span><span class="cx"> _wkSignalCFReadStreamHasBytes
</span><ins>+__ZN7WebCore25HistoryPropertyListWriter12writeObjectsERNS_30BinaryPropertyListObjectStreamE
+__ZN7WebCore25HistoryPropertyListWriter16writeHistoryItemERNS_30BinaryPropertyListObjectStreamEPNS_11HistoryItemE
+__ZTVN7WebCore25HistoryPropertyListWriterE
+__ZN7WebCore25HistoryPropertyListWriter6bufferEm
+__ZN7WebCore25HistoryPropertyListWriterC2Ev
+__ZN7WebCore25HistoryPropertyListWriter11releaseDataEv
</ins></span></pre></div>
<a id="trunkWebCoreWebCorexcodeprojprojectpbxproj"></a>
<div class="modfile"><h4>Modified: trunk/WebCore/WebCore.xcodeproj/project.pbxproj (42371 => 42372)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/WebCore.xcodeproj/project.pbxproj        2009-04-09 22:25:29 UTC (rev 42371)
+++ trunk/WebCore/WebCore.xcodeproj/project.pbxproj        2009-04-09 22:40:05 UTC (rev 42372)
</span><span class="lines">@@ -1974,11 +1974,15 @@
</span><span class="cx">                 935FBC4509BA00B900E230B1 /* EventListener.h in Headers */ = {isa = PBXBuildFile; fileRef = 935FBC4409BA00B900E230B1 /* EventListener.h */; };
</span><span class="cx">                 935FBCF209BA143B00E230B1 /* ExceptionCode.h in Headers */ = {isa = PBXBuildFile; fileRef = 935FBCF109BA143B00E230B1 /* ExceptionCode.h */; };
</span><span class="cx">                 9362640B0DE1137D009D5A00 /* CSSReflectionDirection.h in Headers */ = {isa = PBXBuildFile; fileRef = 9362640A0DE1137D009D5A00 /* CSSReflectionDirection.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><ins>+                9363B62C0F8E8FE000803810 /* HistoryPropertyList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9363B62A0F8E8FE000803810 /* HistoryPropertyList.cpp */; };
+                9363B62D0F8E8FE000803810 /* HistoryPropertyList.h in Headers */ = {isa = PBXBuildFile; fileRef = 9363B62B0F8E8FE000803810 /* HistoryPropertyList.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 93799EF80BF2743600D0F230 /* RenderWordBreak.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93799EF60BF2743600D0F230 /* RenderWordBreak.cpp */; };
</span><span class="cx">                 93799EF90BF2743600D0F230 /* RenderWordBreak.h in Headers */ = {isa = PBXBuildFile; fileRef = 93799EF70BF2743600D0F230 /* RenderWordBreak.h */; };
</span><span class="cx">                 9380F47309A11AB4001FDB34 /* Widget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9380F47109A11AB4001FDB34 /* Widget.cpp */; };
</span><span class="cx">                 9380F47409A11AB4001FDB34 /* Widget.h in Headers */ = {isa = PBXBuildFile; fileRef = 9380F47209A11AB4001FDB34 /* Widget.h */; settings = {ATTRIBUTES = (Private, ); }; };
</span><span class="cx">                 9380F47809A11ACC001FDB34 /* WidgetMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9380F47709A11ACC001FDB34 /* WidgetMac.mm */; };
</span><ins>+                938192030F87E1E600D5352A /* BinaryPropertyList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 938192020F87E1E600D5352A /* BinaryPropertyList.cpp */; };
+                938192050F87E1EC00D5352A /* BinaryPropertyList.h in Headers */ = {isa = PBXBuildFile; fileRef = 938192040F87E1EC00D5352A /* BinaryPropertyList.h */; settings = {ATTRIBUTES = (Private, ); }; };
</ins><span class="cx">                 9382AAB40D8C386100F357A6 /* NodeWithIndex.h in Headers */ = {isa = PBXBuildFile; fileRef = 9382AAB10D8C386100F357A6 /* NodeWithIndex.h */; };
</span><span class="cx">                 93831B570D087D6000E5C984 /* ExceptionCode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93831B560D087D6000E5C984 /* ExceptionCode.cpp */; };
</span><span class="cx">                 938E65F109F09840008A48EC /* JSHTMLElementWrapperFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 938E65F009F09840008A48EC /* JSHTMLElementWrapperFactory.h */; };
</span><span class="lines">@@ -6874,12 +6878,16 @@
</span><span class="cx">                 935FBC4409BA00B900E230B1 /* EventListener.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventListener.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 935FBCF109BA143B00E230B1 /* ExceptionCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExceptionCode.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 9362640A0DE1137D009D5A00 /* CSSReflectionDirection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CSSReflectionDirection.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                9363B62A0F8E8FE000803810 /* HistoryPropertyList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HistoryPropertyList.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                9363B62B0F8E8FE000803810 /* HistoryPropertyList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HistoryPropertyList.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 936DD03A09CEAC270056AE8C /* Range.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Range.idl; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 93799EF60BF2743600D0F230 /* RenderWordBreak.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderWordBreak.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 93799EF70BF2743600D0F230 /* RenderWordBreak.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderWordBreak.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 9380F47109A11AB4001FDB34 /* Widget.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Widget.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 9380F47209A11AB4001FDB34 /* Widget.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Widget.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 9380F47709A11ACC001FDB34 /* WidgetMac.mm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.objcpp; path = WidgetMac.mm; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><ins>+                938192020F87E1E600D5352A /* BinaryPropertyList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BinaryPropertyList.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
+                938192040F87E1EC00D5352A /* BinaryPropertyList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BinaryPropertyList.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</ins><span class="cx">                 9382AAB10D8C386100F357A6 /* NodeWithIndex.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NodeWithIndex.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 93831B560D087D6000E5C984 /* ExceptionCode.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExceptionCode.cpp; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="cx">                 938E65F009F09840008A48EC /* JSHTMLElementWrapperFactory.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSHTMLElementWrapperFactory.h; sourceTree = &quot;&lt;group&gt;&quot;; };
</span><span class="lines">@@ -9588,6 +9596,8 @@
</span><span class="cx">                 1AE42F670AA4B8CB00C8612D /* cf */ = {
</span><span class="cx">                         isa = PBXGroup;
</span><span class="cx">                         children = (
</span><ins>+                                938192040F87E1EC00D5352A /* BinaryPropertyList.h */,
+                                938192020F87E1E600D5352A /* BinaryPropertyList.cpp */,
</ins><span class="cx">                                 5160306B0CC4362300C8AC25 /* FileSystemCF.cpp */,
</span><span class="cx">                                 1A98956A0AA78F80005EF5EF /* KURLCFNet.cpp */,
</span><span class="cx">                                 1C63A2470F71646600C09D5A /* RunLoopTimerCF.cpp */,
</span><span class="lines">@@ -9949,6 +9959,7 @@
</span><span class="cx">                 51741D080B07257000ED442C /* history */ = {
</span><span class="cx">                         isa = PBXGroup;
</span><span class="cx">                         children = (
</span><ins>+                                9363B6290F8E8FE000803810 /* cf */,
</ins><span class="cx">                                 5160F4920B0AA71500C1D2AF /* mac */,
</span><span class="cx">                                 51741D0C0B07259A00ED442C /* BackForwardList.cpp */,
</span><span class="cx">                                 51741D0B0B07259A00ED442C /* BackForwardList.h */,
</span><span class="lines">@@ -11463,6 +11474,15 @@
</span><span class="cx">                         tabWidth = 4;
</span><span class="cx">                         usesTabs = 0;
</span><span class="cx">                 };
</span><ins>+                9363B6290F8E8FE000803810 /* cf */ = {
+                        isa = PBXGroup;
+                        children = (
+                                9363B62A0F8E8FE000803810 /* HistoryPropertyList.cpp */,
+                                9363B62B0F8E8FE000803810 /* HistoryPropertyList.h */,
+                        );
+                        path = cf;
+                        sourceTree = &quot;&lt;group&gt;&quot;;
+                };
</ins><span class="cx">                 93A1EAA20A5634D8006960A0 /* mac */ = {
</span><span class="cx">                         isa = PBXGroup;
</span><span class="cx">                         children = (
</span><span class="lines">@@ -16804,6 +16824,8 @@
</span><span class="cx">                                 1C63A2480F71646600C09D5A /* RunLoopTimer.h in Headers */,
</span><span class="cx">                                 935F45430F7C3B5F00D7C1FB /* JSLazyEventListener.h in Headers */,
</span><span class="cx">                                 93F925430F7EF5B8007E37C9 /* CheckedRadioButtons.h in Headers */,
</span><ins>+                                938192050F87E1EC00D5352A /* BinaryPropertyList.h in Headers */,
+                                9363B62D0F8E8FE000803810 /* HistoryPropertyList.h in Headers */,
</ins><span class="cx">                                 415E3EF60F8D67FE007EEB50 /* MessagePortProxy.h in Headers */,
</span><span class="cx">                         );
</span><span class="cx">                         runOnlyForDeploymentPostprocessing = 0;
</span><span class="lines">@@ -18813,6 +18835,8 @@
</span><span class="cx">                                 1C63A2490F71646600C09D5A /* RunLoopTimerCF.cpp in Sources */,
</span><span class="cx">                                 935F45420F7C3B5F00D7C1FB /* JSLazyEventListener.cpp in Sources */,
</span><span class="cx">                                 93F925440F7EF5B8007E37C9 /* CheckedRadioButtons.cpp in Sources */,
</span><ins>+                                938192030F87E1E600D5352A /* BinaryPropertyList.cpp in Sources */,
+                                9363B62C0F8E8FE000803810 /* HistoryPropertyList.cpp in Sources */,
</ins><span class="cx">                         );
</span><span class="cx">                         runOnlyForDeploymentPostprocessing = 0;
</span><span class="cx">                 };
</span></span></pre></div>
<a id="trunkWebCorehistorycfHistoryPropertyListcpp"></a>
<div class="addfile"><h4>Added: trunk/WebCore/history/cf/HistoryPropertyList.cpp (0 => 42372)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/history/cf/HistoryPropertyList.cpp                                (rev 0)
+++ trunk/WebCore/history/cf/HistoryPropertyList.cpp        2009-04-09 22:40:05 UTC (rev 42372)
</span><span class="lines">@@ -0,0 +1,155 @@
</span><ins>+/*
+ * Copyright (C) 2009 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. ``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
+ * 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. 
+ */
+
+#include &quot;config.h&quot;
+#include &quot;HistoryPropertyList.h&quot;
+
+#include &quot;HistoryItem.h&quot;
+
+namespace WebCore {
+
+static const int currentFileVersion = 1;
+
+HistoryPropertyListWriter::HistoryPropertyListWriter()
+    : m_dailyVisitCountsKey(&quot;D&quot;)
+    , m_displayTitleKey(&quot;displayTitle&quot;)
+    , m_lastVisitWasFailureKey(&quot;lastVisitWasFailure&quot;)
+    , m_lastVisitWasHTTPNonGetKey(&quot;lastVisitWasHTTPNonGet&quot;)
+    , m_lastVisitedDateKey(&quot;lastVisitedDate&quot;)
+    , m_redirectURLsKey(&quot;redirectURLs&quot;)
+    , m_titleKey(&quot;title&quot;)
+    , m_urlKey(&quot;&quot;)
+    , m_visitCountKey(&quot;visitCount&quot;)
+    , m_weeklyVisitCountsKey(&quot;W&quot;)
+    , m_buffer(0)
+{
+}
+
+UInt8* HistoryPropertyListWriter::buffer(size_t size)
+{
+    ASSERT(!m_buffer);
+    m_buffer = static_cast&lt;UInt8*&gt;(CFAllocatorAllocate(0, size, 0));
+    m_bufferSize = size;
+    return m_buffer;
+}
+
+RetainPtr&lt;CFDataRef&gt; HistoryPropertyListWriter::releaseData()
+{
+    UInt8* buffer = m_buffer;
+    if (!buffer)
+        return 0;
+    m_buffer = 0;
+    RetainPtr&lt;CFDataRef&gt; data(AdoptCF, CFDataCreateWithBytesNoCopy(0, buffer, m_bufferSize, 0));
+    if (!data) {
+        CFAllocatorDeallocate(0, buffer);
+        return 0;
+    }
+    return data;
+}
+
+void HistoryPropertyListWriter::writeObjects(BinaryPropertyListObjectStream&amp; stream)
+{
+    size_t outerDictionaryStart = stream.writeDictionaryStart();
+
+    stream.writeString(&quot;WebHistoryFileVersion&quot;);
+    stream.writeString(&quot;WebHistoryDates&quot;);
+
+    stream.writeInteger(currentFileVersion);
+    size_t outerDateArrayStart = stream.writeArrayStart();
+    writeHistoryItems(stream);
+    stream.writeArrayEnd(outerDateArrayStart);
+
+    stream.writeDictionaryEnd(outerDictionaryStart);
+}
+
+void HistoryPropertyListWriter::writeHistoryItem(BinaryPropertyListObjectStream&amp; stream, HistoryItem* item)
+{
+    size_t itemDictionaryStart = stream.writeDictionaryStart();
+
+    const String&amp; title = item-&gt;title();
+    const String&amp; displayTitle = item-&gt;alternateTitle();
+    double lastVisitedDate = item-&gt;lastVisitedTime();
+    int visitCount = item-&gt;visitCount();
+    Vector&lt;String&gt;* redirectURLs = item-&gt;redirectURLs();
+    const Vector&lt;int&gt;&amp; dailyVisitCounts = item-&gt;dailyVisitCounts();
+    const Vector&lt;int&gt;&amp; weeklyVisitCounts = item-&gt;weeklyVisitCounts();
+
+    // keys
+    stream.writeString(m_urlKey);
+    if (!title.isEmpty())
+        stream.writeString(m_titleKey);
+    if (!displayTitle.isEmpty())
+        stream.writeString(m_displayTitleKey);
+    if (lastVisitedDate)
+        stream.writeString(m_lastVisitedDateKey);
+    if (visitCount)
+        stream.writeString(m_visitCountKey);
+    if (item-&gt;lastVisitWasFailure())
+        stream.writeString(m_lastVisitWasFailureKey);
+    if (item-&gt;lastVisitWasHTTPNonGet())
+        stream.writeString(m_lastVisitWasHTTPNonGetKey);
+    if (redirectURLs)
+        stream.writeString(m_redirectURLsKey);
+    if (!dailyVisitCounts.isEmpty())
+        stream.writeString(m_dailyVisitCountsKey);
+    if (!weeklyVisitCounts.isEmpty())
+        stream.writeString(m_weeklyVisitCountsKey);
+
+    // values
+    stream.writeUniqueString(item-&gt;urlString());
+    if (!title.isEmpty())
+        stream.writeString(title);
+    if (!displayTitle.isEmpty())
+        stream.writeString(displayTitle);
+    if (lastVisitedDate) {
+        char buffer[32];
+        snprintf(buffer, sizeof(buffer), &quot;%.1lf&quot;, lastVisitedDate);
+        stream.writeUniqueString(buffer);
+    }
+    if (visitCount)
+        stream.writeInteger(visitCount);
+    if (item-&gt;lastVisitWasFailure())
+        stream.writeBooleanTrue();
+    if (item-&gt;lastVisitWasHTTPNonGet()) {
+        ASSERT(item-&gt;urlString().startsWith(&quot;http:&quot;, false) || item-&gt;urlString().startsWith(&quot;https:&quot;, false));
+        stream.writeBooleanTrue();
+    }
+    if (redirectURLs) {
+        size_t redirectArrayStart = stream.writeArrayStart();
+        size_t size = redirectURLs-&gt;size();
+        ASSERT(size);
+        for (size_t i = 0; i &lt; size; ++i)
+            stream.writeUniqueString(redirectURLs-&gt;at(i));
+        stream.writeArrayEnd(redirectArrayStart);
+    }
+    if (size_t size = dailyVisitCounts.size())
+        stream.writeIntegerArray(dailyVisitCounts.data(), size);
+    if (size_t size = weeklyVisitCounts.size())
+        stream.writeIntegerArray(weeklyVisitCounts.data(), size);
+
+    stream.writeDictionaryEnd(itemDictionaryStart);
+}
+
+}
</ins><span class="cx">Property changes on: trunk/WebCore/history/cf/HistoryPropertyList.cpp
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<a id="trunkWebCorehistorycfHistoryPropertyListh"></a>
<div class="addfile"><h4>Added: trunk/WebCore/history/cf/HistoryPropertyList.h (0 => 42372)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/history/cf/HistoryPropertyList.h                                (rev 0)
+++ trunk/WebCore/history/cf/HistoryPropertyList.h        2009-04-09 22:40:05 UTC (rev 42372)
</span><span class="lines">@@ -0,0 +1,69 @@
</span><ins>+/*
+ * Copyright (C) 2009 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. ``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
+ * 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 HistoryPropertyList_h
+#define HistoryPropertyList_h
+
+#include &quot;BinaryPropertyList.h&quot;
+#include &quot;PlatformString.h&quot;
+#include &lt;wtf/RetainPtr.h&gt;
+
+namespace WebCore {
+
+class HistoryItem;
+
+class HistoryPropertyListWriter : public BinaryPropertyListWriter {
+public:
+    RetainPtr&lt;CFDataRef&gt; releaseData();
+
+protected:
+    HistoryPropertyListWriter();
+
+    void writeHistoryItem(BinaryPropertyListObjectStream&amp;, HistoryItem*);
+
+private:
+    virtual void writeHistoryItems(BinaryPropertyListObjectStream&amp;) = 0;
+
+    virtual void writeObjects(BinaryPropertyListObjectStream&amp;);
+    virtual UInt8* buffer(size_t);
+
+    const String m_dailyVisitCountsKey;
+    const String m_displayTitleKey;
+    const String m_lastVisitWasFailureKey;
+    const String m_lastVisitWasHTTPNonGetKey;
+    const String m_lastVisitedDateKey;
+    const String m_redirectURLsKey;
+    const String m_titleKey;
+    const String m_urlKey;
+    const String m_visitCountKey;
+    const String m_weeklyVisitCountsKey;
+
+    UInt8* m_buffer;
+    size_t m_bufferSize;
+};
+
+}
+
+#endif
</ins><span class="cx">Property changes on: trunk/WebCore/history/cf/HistoryPropertyList.h
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<a id="trunkWebCoreplatformcfBinaryPropertyListcpp"></a>
<div class="addfile"><h4>Added: trunk/WebCore/platform/cf/BinaryPropertyList.cpp (0 => 42372)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/platform/cf/BinaryPropertyList.cpp                                (rev 0)
+++ trunk/WebCore/platform/cf/BinaryPropertyList.cpp        2009-04-09 22:40:05 UTC (rev 42372)
</span><span class="lines">@@ -0,0 +1,811 @@
</span><ins>+/*
+ * Copyright (C) 2009 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. ``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
+ * 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. 
+ */
+
+#include &quot;config.h&quot;
+#include &quot;BinaryPropertyList.h&quot;
+
+#include &quot;StringHash.h&quot;
+#include &lt;wtf/HashSet.h&gt;
+#include &lt;limits&gt;
+
+using namespace std;
+
+namespace WebCore {
+
+static const size_t headerSize = 8;
+static const size_t trailerSize = 32;
+
+static const UInt8 booleanTrueMarkerByte = 0x09;
+static const UInt8 oneByteIntegerMarkerByte = 0x10;
+static const UInt8 twoByteIntegerMarkerByte = 0x11;
+static const UInt8 fourByteIntegerMarkerByte = 0x12;
+static const UInt8 eightByteIntegerMarkerByte = 0x13;
+static const UInt8 asciiStringMarkerByte = 0x50;
+static const UInt8 asciiStringWithSeparateLengthMarkerByte = 0x5F;
+static const UInt8 unicodeStringMarkerByte = 0x60;
+static const UInt8 unicodeStringWithSeparateLengthMarkerByte = 0x6F;
+static const UInt8 arrayMarkerByte = 0xA0;
+static const UInt8 arrayWithSeparateLengthMarkerByte = 0xAF;
+static const UInt8 dictionaryMarkerByte = 0xD0;
+static const UInt8 dictionaryWithSeparateLengthMarkerByte = 0xDF;
+static const size_t maxLengthInMarkerByte = 0xE;
+
+class IntegerArray {
+public:
+    IntegerArray() : m_integers(0), m_size(0) { }
+    IntegerArray(const int* integers, size_t size) : m_integers(integers), m_size(size) { ASSERT(integers); ASSERT(size); }
+
+    void markDeleted() { m_integers = 0; m_size = deletedValueSize(); }
+    bool isDeletedValue() const { return m_size == deletedValueSize(); }
+
+    const int* integers() const { ASSERT(!isDeletedValue()); return m_integers; }
+    size_t size() const { ASSERT(!isDeletedValue()); return m_size; }
+
+private:
+    static size_t deletedValueSize() { return numeric_limits&lt;size_t&gt;::max(); }
+
+    friend bool operator==(const IntegerArray&amp;, const IntegerArray&amp;);
+
+    const int* m_integers;
+    size_t m_size;
+};
+
+inline bool operator==(const IntegerArray&amp; a, const IntegerArray&amp; b)
+{
+    return a.m_integers == b.m_integers &amp;&amp;  a.m_size == b.m_size;
+}
+
+struct IntegerArrayHashTraits : WTF::GenericHashTraits&lt;IntegerArray&gt; {
+    static const bool needsDestruction = false;
+    static void constructDeletedValue(IntegerArray&amp; slot) { slot.markDeleted(); }
+    static bool isDeletedValue(const IntegerArray&amp; array) { return array.isDeletedValue(); }
+};
+
+struct IntegerArrayHash {
+    static unsigned hash(const IntegerArray&amp;);
+    static bool equal(const IntegerArray&amp;, const IntegerArray&amp;);
+    static const bool safeToCompareToEmptyOrDeleted = true;
+};
+
+unsigned IntegerArrayHash::hash(const IntegerArray&amp; array)
+{
+    return StringImpl::computeHash(reinterpret_cast&lt;const UChar*&gt;(array.integers()), array.size() / (sizeof(int) / sizeof(UChar)));
+}
+
+bool IntegerArrayHash::equal(const IntegerArray&amp; a, const IntegerArray&amp; b)
+{
+    if (a.isDeletedValue() || b.isDeletedValue())
+        return a.isDeletedValue() == b.isDeletedValue();
+    if (a.size() != b.size())
+        return false;
+    for (size_t i = 0; i &lt; a.size(); ++i) {
+        if (a.integers()[i] != b.integers()[i])
+            return false;
+    }
+    return true;
+}
+
+typedef size_t ObjectReference;
+
+class BinaryPropertyListPlan : private BinaryPropertyListObjectStream {
+public:
+    BinaryPropertyListPlan(BinaryPropertyListWriter&amp;);
+
+    ObjectReference booleanTrueObjectReference() const;
+    ObjectReference integerObjectReference(int) const;
+    ObjectReference stringObjectReference(const String&amp;) const;
+    ObjectReference integerArrayObjectReference(const int*, size_t) const;
+
+    ObjectReference objectCount() const { return m_currentObjectReference; }
+
+    ObjectReference byteCount() const { return m_byteCount; }
+    ObjectReference objectReferenceCount() const { return m_objectReferenceCount; }
+
+private:
+    virtual void writeBooleanTrue();
+    virtual void writeInteger(int);
+    virtual void writeString(const String&amp;);
+    virtual void writeIntegerArray(const int*, size_t);
+    virtual void writeUniqueString(const String&amp;);
+    virtual void writeUniqueString(const char*);
+    virtual size_t writeArrayStart();
+    virtual void writeArrayEnd(size_t);
+    virtual size_t writeDictionaryStart();
+    virtual void writeDictionaryEnd(size_t);
+
+    void writeArrayObject(size_t);
+    void writeDictionaryObject(size_t);
+    void writeStringObject(const String&amp;);
+    void writeStringObject(const char*);
+
+    static ObjectReference invalidObjectReference() { return numeric_limits&lt;ObjectReference&gt;::max(); }
+
+    typedef HashMap&lt;IntegerArray, ObjectReference, IntegerArrayHash, IntegerArrayHashTraits&gt; IntegerArrayMap;
+
+    ObjectReference m_booleanTrueObjectReference;
+    ObjectReference m_integerNegativeOneObjectReference;
+    ObjectReference m_integerZeroObjectReference;
+    HashMap&lt;int, ObjectReference&gt; m_integers;
+    HashMap&lt;String, ObjectReference&gt; m_strings;
+    IntegerArrayMap m_integerArrays;
+
+    ObjectReference m_currentObjectReference;
+
+    size_t m_currentAggregateSize;
+
+    size_t m_byteCount;
+    size_t m_objectReferenceCount;
+};
+
+BinaryPropertyListPlan::BinaryPropertyListPlan(BinaryPropertyListWriter&amp; client)
+    : m_booleanTrueObjectReference(invalidObjectReference())
+    , m_integerNegativeOneObjectReference(invalidObjectReference())
+    , m_integerZeroObjectReference(invalidObjectReference())
+    , m_currentObjectReference(0)
+    , m_currentAggregateSize(0)
+    , m_byteCount(0)
+    , m_objectReferenceCount(0)
+{
+    client.writeObjects(*this);
+    ASSERT(m_currentAggregateSize == 1);
+}
+
+void BinaryPropertyListPlan::writeBooleanTrue()
+{
+    ++m_currentAggregateSize;
+    if (m_booleanTrueObjectReference != invalidObjectReference())
+        return;
+    m_booleanTrueObjectReference = m_currentObjectReference++;
+    ++m_byteCount;
+}
+
+static inline int integerByteCount(size_t integer)
+{
+    if (integer &lt;= 0xFF)
+        return 2;
+    if (integer &lt;= 0xFFFF)
+        return 3;
+#ifdef __LP64__
+    if (integer &lt;= 0xFFFFFFFFULL)
+        return 5;
+    return 9;
+#else
+    return 5;
+#endif
+}
+
+void BinaryPropertyListPlan::writeInteger(int integer)
+{
+    ASSERT(integer &gt;= 0);
+    ++m_currentAggregateSize;
+    switch (integer) {
+        case -1:
+            if (m_integerNegativeOneObjectReference != invalidObjectReference())
+                return;
+            m_integerNegativeOneObjectReference = m_currentObjectReference;
+            break;
+        case 0:
+            if (m_integerZeroObjectReference != invalidObjectReference())
+                return;
+            m_integerZeroObjectReference = m_currentObjectReference;
+            break;
+        default:
+            if (!m_integers.add(integer, m_currentObjectReference).second)
+                return;
+            break;
+    }
+    ++m_currentObjectReference;
+    m_byteCount += integerByteCount(integer);
+}
+
+void BinaryPropertyListPlan::writeString(const String&amp; string)
+{
+    ++m_currentAggregateSize;
+    if (!m_strings.add(string, m_currentObjectReference).second)
+        return;
+    ++m_currentObjectReference;
+    writeStringObject(string);
+}
+
+void BinaryPropertyListPlan::writeIntegerArray(const int* integers, size_t size)
+{
+    size_t savedAggregateSize = ++m_currentAggregateSize;
+    ASSERT(size);
+    pair&lt;IntegerArrayMap::iterator, bool&gt; addResult = m_integerArrays.add(IntegerArray(integers, size), 0);
+    if (!addResult.second)
+        return;
+    for (size_t i = 0; i &lt; size; ++i)
+        writeInteger(integers[i]);
+    addResult.first-&gt;second = m_currentObjectReference++;
+    writeArrayObject(size);
+    m_currentAggregateSize = savedAggregateSize;
+}
+
+void BinaryPropertyListPlan::writeUniqueString(const String&amp; string)
+{
+    ++m_currentAggregateSize;
+    ++m_currentObjectReference;
+    writeStringObject(string);
+}
+
+void BinaryPropertyListPlan::writeUniqueString(const char* string)
+{
+    ++m_currentAggregateSize;
+    ++m_currentObjectReference;
+    writeStringObject(string);
+}
+
+size_t BinaryPropertyListPlan::writeArrayStart()
+{
+    size_t savedAggregateSize = m_currentAggregateSize;
+    m_currentAggregateSize = 0;
+    return savedAggregateSize;
+}
+
+void BinaryPropertyListPlan::writeArrayEnd(size_t savedAggregateSize)
+{
+    ++m_currentObjectReference;
+    writeArrayObject(m_currentAggregateSize);
+    m_currentAggregateSize = savedAggregateSize + 1;
+}
+
+size_t BinaryPropertyListPlan::writeDictionaryStart()
+{
+    size_t savedAggregateSize = m_currentAggregateSize;
+    m_currentAggregateSize = 0;
+    return savedAggregateSize;
+}
+
+void BinaryPropertyListPlan::writeDictionaryEnd(size_t savedAggregateSize)
+{
+    ++m_currentObjectReference;
+    writeDictionaryObject(m_currentAggregateSize);
+    m_currentAggregateSize = savedAggregateSize + 1;
+}
+
+static size_t markerPlusLengthByteCount(size_t length)
+{
+    if (length &lt;= maxLengthInMarkerByte)
+        return 1;
+    return 1 + integerByteCount(length);
+}
+
+void BinaryPropertyListPlan::writeStringObject(const String&amp; string)
+{
+    const UChar* characters = string.characters();
+    unsigned length = string.length();
+    m_byteCount += markerPlusLengthByteCount(length) + length;
+    if (!charactersAreAllASCII(characters, length))
+        m_byteCount += length;
+}
+
+void BinaryPropertyListPlan::writeStringObject(const char* string)
+{
+    unsigned length = strlen(string);
+    m_byteCount += markerPlusLengthByteCount(length) + length;
+}
+
+void BinaryPropertyListPlan::writeArrayObject(size_t size)
+{
+    ASSERT(size);
+    m_byteCount += markerPlusLengthByteCount(size);
+    m_objectReferenceCount += size;
+}
+
+void BinaryPropertyListPlan::writeDictionaryObject(size_t size)
+{
+    ASSERT(size);
+    ASSERT(!(size &amp; 1));
+    m_byteCount += markerPlusLengthByteCount(size / 2);
+    m_objectReferenceCount += size;
+}
+
+ObjectReference BinaryPropertyListPlan::booleanTrueObjectReference() const
+{
+    ASSERT(m_booleanTrueObjectReference != invalidObjectReference());
+    return m_booleanTrueObjectReference;
+}
+
+ObjectReference BinaryPropertyListPlan::integerObjectReference(int integer) const
+{
+    switch (integer) {
+        case -1:
+            ASSERT(m_integerNegativeOneObjectReference != invalidObjectReference());
+            return m_integerNegativeOneObjectReference;
+        case 0:
+            ASSERT(m_integerZeroObjectReference != invalidObjectReference());
+            return m_integerZeroObjectReference;
+        default:
+            ASSERT(m_integers.contains(integer));
+            return m_integers.get(integer);
+    }
+}
+
+ObjectReference BinaryPropertyListPlan::stringObjectReference(const String&amp; string) const
+{
+    ASSERT(m_strings.contains(string));
+    return m_strings.get(string);
+}
+
+ObjectReference BinaryPropertyListPlan::integerArrayObjectReference(const int* integers, size_t size) const
+{
+    ASSERT(m_integerArrays.contains(IntegerArray(integers, size)));
+    return m_integerArrays.get(IntegerArray(integers, size));
+}
+
+class BinaryPropertyListSerializer : private BinaryPropertyListObjectStream {
+public:
+    BinaryPropertyListSerializer(BinaryPropertyListWriter&amp;);
+
+private:
+    virtual void writeBooleanTrue();
+    virtual void writeInteger(int);
+    virtual void writeString(const String&amp;);
+    virtual void writeIntegerArray(const int*, size_t);
+    virtual void writeUniqueString(const String&amp;);
+    virtual void writeUniqueString(const char*);
+    virtual size_t writeArrayStart();
+    virtual void writeArrayEnd(size_t);
+    virtual size_t writeDictionaryStart();
+    virtual void writeDictionaryEnd(size_t);
+
+    void appendIntegerObject(int);
+    void appendStringObject(const String&amp;);
+    void appendStringObject(const char*);
+    void appendIntegerArrayObject(const int*, size_t);
+
+    void appendByte(unsigned char);
+    void appendByte(unsigned);
+    void appendByte(unsigned long);
+    void appendByte(int);
+
+    void appendInteger(size_t);
+
+    void appendObjectReference(ObjectReference);
+
+    void addAggregateObjectReference(ObjectReference);
+
+    void startObject();
+
+    const BinaryPropertyListPlan m_plan;
+    const int m_objectReferenceSize;
+    const size_t m_offsetTableStart;
+    const int m_offsetSize;
+    const size_t m_bufferSize;
+    UInt8* const m_buffer;
+
+    UInt8* m_currentByte;
+    ObjectReference m_currentObjectReference;
+    UInt8* m_currentAggregateBufferByte;
+};
+
+inline void BinaryPropertyListSerializer::appendByte(unsigned char byte)
+{
+    *m_currentByte++ = byte;
+    ASSERT(m_currentByte &lt;= m_currentAggregateBufferByte);
+}
+
+inline void BinaryPropertyListSerializer::appendByte(unsigned byte)
+{
+    *m_currentByte++ = byte;
+    ASSERT(m_currentByte &lt;= m_currentAggregateBufferByte);
+}
+
+inline void BinaryPropertyListSerializer::appendByte(unsigned long byte)
+{
+    *m_currentByte++ = byte;
+    ASSERT(m_currentByte &lt;= m_currentAggregateBufferByte);
+}
+
+inline void BinaryPropertyListSerializer::appendByte(int byte)
+{
+    *m_currentByte++ = byte;
+    ASSERT(m_currentByte &lt;= m_currentAggregateBufferByte);
+}
+
+static int bytesNeeded(size_t count)
+{
+    ASSERT(count);
+    int bytesNeeded = 1;
+    for (size_t mask = numeric_limits&lt;size_t&gt;::max() &lt;&lt; 8; count &amp; mask; mask &lt;&lt;= 8)
+        ++bytesNeeded;
+    return bytesNeeded;
+}
+
+static inline void storeLength(UInt8* destination, size_t length)
+{
+#ifdef __LP64__
+    destination[0] = length &gt;&gt; 56;
+    destination[1] = length &gt;&gt; 48;
+    destination[2] = length &gt;&gt; 40;
+    destination[3] = length &gt;&gt; 32;
+#else
+    destination[0] = 0;
+    destination[1] = 0;
+    destination[2] = 0;
+    destination[3] = 0;
+#endif
+    destination[4] = length &gt;&gt; 24;
+    destination[5] = length &gt;&gt; 16;
+    destination[6] = length &gt;&gt; 8;
+    destination[7] = length;
+}
+
+// Like memmove, but reverses the bytes.
+static void moveAndReverseBytes(UInt8* destination, const UInt8* source, size_t length)
+{
+    ASSERT(length);
+    memmove(destination, source, length);
+    UInt8* start = destination;
+    UInt8* end = destination + length;
+    while (end - start &gt; 1)
+        std::swap(*start++, *--end);
+}
+
+BinaryPropertyListSerializer::BinaryPropertyListSerializer(BinaryPropertyListWriter&amp; client)
+    : m_plan(client)
+    , m_objectReferenceSize(bytesNeeded(m_plan.objectCount()))
+    , m_offsetTableStart(headerSize + m_plan.byteCount() + m_plan.objectReferenceCount() * m_objectReferenceSize)
+    , m_offsetSize(bytesNeeded(m_offsetTableStart))
+    , m_bufferSize(m_offsetTableStart + m_plan.objectCount() * m_offsetSize + trailerSize)
+    , m_buffer(client.buffer(m_bufferSize))
+    , m_currentObjectReference(0)
+{
+    ASSERT(m_objectReferenceSize &gt; 0);
+    ASSERT(m_offsetSize &gt; 0);
+
+#ifdef __LP64__
+    ASSERT(m_objectReferenceSize &lt;= 8);
+    ASSERT(m_offsetSize &lt;= 8);
+#else
+    ASSERT(m_objectReferenceSize &lt;= 4);
+    ASSERT(m_offsetSize &lt;= 4);
+#endif
+
+    if (!m_buffer)
+        return;
+
+    // Write objects and offset table.
+    m_currentByte = m_buffer + headerSize;
+    m_currentAggregateBufferByte = m_buffer + m_offsetTableStart;
+    client.writeObjects(*this);
+    ASSERT(m_currentObjectReference == m_plan.objectCount());
+    ASSERT(m_currentAggregateBufferByte == m_buffer + m_offsetTableStart);
+    ASSERT(m_currentByte == m_buffer + m_offsetTableStart);
+
+    // Write header.
+    memcpy(m_buffer, &quot;bplist00&quot;, headerSize);
+
+    // Write trailer.
+    UInt8* trailer = m_buffer + m_bufferSize - trailerSize;
+    memset(trailer, 0, 6);
+    trailer[6] = m_offsetSize;
+    trailer[7] = m_objectReferenceSize;
+    storeLength(trailer + 8, m_plan.objectCount());
+    storeLength(trailer + 16, m_plan.objectCount() - 1);
+    storeLength(trailer + 24, m_offsetTableStart);
+}
+
+void BinaryPropertyListSerializer::writeBooleanTrue()
+{
+    ObjectReference reference = m_plan.booleanTrueObjectReference();
+    if (m_currentObjectReference != reference)
+        ASSERT(reference &lt; m_currentObjectReference);
+    else {
+        startObject();
+        appendByte(booleanTrueMarkerByte);
+    }
+    addAggregateObjectReference(reference);
+}
+
+void BinaryPropertyListSerializer::writeInteger(int integer)
+{
+    ObjectReference reference = m_plan.integerObjectReference(integer);
+    if (m_currentObjectReference != reference)
+        ASSERT(reference &lt; m_currentObjectReference);
+    else
+        appendIntegerObject(integer);
+    addAggregateObjectReference(reference);
+}
+
+void BinaryPropertyListSerializer::writeString(const String&amp; string)
+{
+    ObjectReference reference = m_plan.stringObjectReference(string);
+    if (m_currentObjectReference != reference)
+        ASSERT(reference &lt; m_currentObjectReference);
+    else
+        appendStringObject(string);
+    addAggregateObjectReference(reference);
+}
+
+void BinaryPropertyListSerializer::writeIntegerArray(const int* integers, size_t size)
+{
+    ObjectReference reference = m_plan.integerArrayObjectReference(integers, size);
+    UInt8* savedAggregateBufferByte = m_currentAggregateBufferByte;
+    for (size_t i = 0; i &lt; size; ++i)
+        writeInteger(integers[i]);
+    m_currentAggregateBufferByte = savedAggregateBufferByte;
+    ASSERT(m_currentByte &lt;= m_currentAggregateBufferByte);
+    if (m_currentObjectReference != reference)
+        ASSERT(reference &lt; m_currentObjectReference);
+    else
+        appendIntegerArrayObject(integers, size);
+    addAggregateObjectReference(reference);
+}
+
+void BinaryPropertyListSerializer::writeUniqueString(const char* string)
+{
+    addAggregateObjectReference(m_currentObjectReference);
+    appendStringObject(string);
+}
+
+void BinaryPropertyListSerializer::writeUniqueString(const String&amp; string)
+{
+    addAggregateObjectReference(m_currentObjectReference);
+    appendStringObject(string);
+}
+
+size_t BinaryPropertyListSerializer::writeArrayStart()
+{
+    return m_currentAggregateBufferByte - m_buffer;
+}
+
+void BinaryPropertyListSerializer::writeArrayEnd(size_t savedAggregateBufferOffset)
+{
+    ObjectReference reference = m_currentObjectReference;
+    startObject();
+    size_t aggregateBufferByteCount = savedAggregateBufferOffset - (m_currentAggregateBufferByte - m_buffer);
+    ASSERT(aggregateBufferByteCount);
+    ASSERT(!(aggregateBufferByteCount % m_objectReferenceSize));
+    size_t size = aggregateBufferByteCount / m_objectReferenceSize;
+    if (size &lt;= maxLengthInMarkerByte)
+        appendByte(arrayMarkerByte | size);
+    else {
+        appendByte(arrayWithSeparateLengthMarkerByte);
+        appendInteger(size);
+    }
+    m_currentAggregateBufferByte = m_buffer + savedAggregateBufferOffset;
+    ASSERT(m_currentByte &lt;= m_currentAggregateBufferByte);
+    moveAndReverseBytes(m_currentByte, m_currentAggregateBufferByte - aggregateBufferByteCount, aggregateBufferByteCount);
+    m_currentByte += aggregateBufferByteCount;
+    ASSERT(m_currentByte &lt;= m_currentAggregateBufferByte);
+    if (m_currentObjectReference &lt; m_plan.objectCount())
+        addAggregateObjectReference(reference);
+    else
+        ASSERT(m_currentObjectReference == m_plan.objectCount());
+}
+
+size_t BinaryPropertyListSerializer::writeDictionaryStart()
+{
+    return m_currentAggregateBufferByte - m_buffer;
+}
+
+void BinaryPropertyListSerializer::writeDictionaryEnd(size_t savedAggregateBufferOffset)
+{
+    ObjectReference reference = m_currentObjectReference;
+    startObject();
+    size_t aggregateBufferByteCount = savedAggregateBufferOffset - (m_currentAggregateBufferByte - m_buffer);
+    ASSERT(aggregateBufferByteCount);
+    ASSERT(!(aggregateBufferByteCount % (m_objectReferenceSize * 2)));
+    size_t size = aggregateBufferByteCount / (m_objectReferenceSize * 2);
+    if (size &lt;= maxLengthInMarkerByte)
+        appendByte(dictionaryMarkerByte | size);
+    else {
+        appendByte(dictionaryWithSeparateLengthMarkerByte);
+        appendInteger(size);
+    }
+    m_currentAggregateBufferByte = m_buffer + savedAggregateBufferOffset;
+    ASSERT(m_currentByte &lt;= m_currentAggregateBufferByte);
+    moveAndReverseBytes(m_currentByte, m_currentAggregateBufferByte - aggregateBufferByteCount, aggregateBufferByteCount);
+    m_currentByte += aggregateBufferByteCount;
+    ASSERT(m_currentByte &lt;= m_currentAggregateBufferByte);
+    if (m_currentObjectReference != m_plan.objectCount())
+        addAggregateObjectReference(reference);
+    else
+        ASSERT(m_currentObjectReference == m_plan.objectCount());
+}
+
+void BinaryPropertyListSerializer::appendIntegerObject(int integer)
+{
+    startObject();
+    ASSERT(integer &gt;= 0);
+    appendInteger(integer);
+}
+
+void BinaryPropertyListSerializer::appendInteger(size_t integer)
+{
+    if (integer &lt;= 0xFF) {
+        appendByte(oneByteIntegerMarkerByte);
+        appendByte(integer);
+        return;
+    }
+    if (integer &lt;= 0xFFFF) {
+        appendByte(twoByteIntegerMarkerByte);
+        appendByte(integer &gt;&gt; 8);
+        appendByte(integer);
+        return;
+    }
+#ifdef __LP64__
+    if (integer &lt;= 0xFFFFFFFFULL) {
+#endif
+        appendByte(fourByteIntegerMarkerByte);
+        appendByte(integer &gt;&gt; 24);
+        appendByte(integer &gt;&gt; 16);
+        appendByte(integer &gt;&gt; 8);
+        appendByte(integer);
+#ifdef __LP64__
+        return;
+    }
+    appendByte(eightByteIntegerMarkerByte);
+    appendByte(integer &gt;&gt; 56);
+    appendByte(integer &gt;&gt; 48);
+    appendByte(integer &gt;&gt; 40);
+    appendByte(integer &gt;&gt; 32);
+    appendByte(integer &gt;&gt; 24);
+    appendByte(integer &gt;&gt; 16);
+    appendByte(integer &gt;&gt; 8);
+    appendByte(integer);
+#endif
+}
+
+void BinaryPropertyListSerializer::appendStringObject(const String&amp; string)
+{
+    startObject();
+    const UChar* characters = string.characters();
+    unsigned length = string.length();
+    if (charactersAreAllASCII(characters, length)) {
+        if (length &lt;= maxLengthInMarkerByte)
+            appendByte(asciiStringMarkerByte | length);
+        else {
+            appendByte(asciiStringWithSeparateLengthMarkerByte);
+            appendInteger(length);
+        }
+        for (unsigned i = 0; i &lt; length; ++i)
+            appendByte(characters[i]);
+    } else {
+        if (length &lt;= maxLengthInMarkerByte)
+            appendByte(unicodeStringMarkerByte | length);
+        else {
+            appendByte(unicodeStringWithSeparateLengthMarkerByte);
+            appendInteger(length);
+        }
+        for (unsigned i = 0; i &lt; length; ++i) {
+            appendByte(characters[i] &gt;&gt; 8);
+            appendByte(characters[i]);
+        }
+    }
+}
+
+void BinaryPropertyListSerializer::appendStringObject(const char* string)
+{
+    startObject();
+    unsigned length = strlen(string);
+    if (length &lt;= maxLengthInMarkerByte)
+        appendByte(asciiStringMarkerByte | length);
+    else {
+        appendByte(asciiStringWithSeparateLengthMarkerByte);
+        appendInteger(length);
+    }
+    for (unsigned i = 0; i &lt; length; ++i)
+        appendByte(string[i]);
+}
+
+void BinaryPropertyListSerializer::appendIntegerArrayObject(const int* integers, size_t size)
+{
+    startObject();
+    if (size &lt;= maxLengthInMarkerByte)
+        appendByte(arrayMarkerByte | size);
+    else {
+        appendByte(arrayWithSeparateLengthMarkerByte);
+        appendInteger(size);
+    }
+    for (unsigned i = 0; i &lt; size; ++i)
+        appendObjectReference(m_plan.integerObjectReference(integers[i]));
+}
+
+void BinaryPropertyListSerializer::appendObjectReference(ObjectReference reference)
+{
+    switch (m_objectReferenceSize) {
+#ifdef __LP64__
+        case 8:
+            appendByte(reference &gt;&gt; 56);
+        case 7:
+            appendByte(reference &gt;&gt; 48);
+        case 6:
+            appendByte(reference &gt;&gt; 40);
+        case 5:
+            appendByte(reference &gt;&gt; 32);
+#endif
+        case 4:
+            appendByte(reference &gt;&gt; 24);
+        case 3:
+            appendByte(reference &gt;&gt; 16);
+        case 2:
+            appendByte(reference &gt;&gt; 8);
+        case 1:
+            appendByte(reference);
+    }
+}
+
+void BinaryPropertyListSerializer::startObject()
+{
+    ObjectReference reference = m_currentObjectReference++;
+
+    size_t offset = m_currentByte - m_buffer;
+
+    UInt8* offsetTableEntry = m_buffer + m_offsetTableStart + reference * m_offsetSize + m_offsetSize;
+    switch (m_offsetSize) {
+#ifdef __LP64__
+        case 8:
+            offsetTableEntry[-8] = offset &gt;&gt; 56;
+        case 7:
+            offsetTableEntry[-7] = offset &gt;&gt; 48;
+        case 6:
+            offsetTableEntry[-6] = offset &gt;&gt; 40;
+        case 5:
+            offsetTableEntry[-5] = offset &gt;&gt; 32;
+#endif
+        case 4:
+            offsetTableEntry[-4] = offset &gt;&gt; 24;
+        case 3:
+            offsetTableEntry[-3] = offset &gt;&gt; 16;
+        case 2:
+            offsetTableEntry[-2] = offset &gt;&gt; 8;
+        case 1:
+            offsetTableEntry[-1] = offset;
+    }
+}
+
+void BinaryPropertyListSerializer::addAggregateObjectReference(ObjectReference reference)
+{
+    switch (m_objectReferenceSize) {
+#ifdef __LP64__
+        case 8:
+            *--m_currentAggregateBufferByte = reference &gt;&gt; 56;
+        case 7:
+            *--m_currentAggregateBufferByte = reference &gt;&gt; 48;
+        case 6:
+            *--m_currentAggregateBufferByte = reference &gt;&gt; 40;
+        case 5:
+            *--m_currentAggregateBufferByte = reference &gt;&gt; 32;
+#endif
+        case 4:
+            *--m_currentAggregateBufferByte = reference &gt;&gt; 24;
+        case 3:
+            *--m_currentAggregateBufferByte = reference &gt;&gt; 16;
+        case 2:
+            *--m_currentAggregateBufferByte = reference &gt;&gt; 8;
+        case 1:
+            *--m_currentAggregateBufferByte = reference;
+    }
+    ASSERT(m_currentByte &lt;= m_currentAggregateBufferByte);
+}
+
+void BinaryPropertyListWriter::writePropertyList()
+{
+    BinaryPropertyListSerializer(*this);
+}
+
+}
</ins><span class="cx">Property changes on: trunk/WebCore/platform/cf/BinaryPropertyList.cpp
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<a id="trunkWebCoreplatformcfBinaryPropertyListh"></a>
<div class="addfile"><h4>Added: trunk/WebCore/platform/cf/BinaryPropertyList.h (0 => 42372)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebCore/platform/cf/BinaryPropertyList.h                                (rev 0)
+++ trunk/WebCore/platform/cf/BinaryPropertyList.h        2009-04-09 22:40:05 UTC (rev 42372)
</span><span class="lines">@@ -0,0 +1,108 @@
</span><ins>+/*
+ * Copyright (C) 2009 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. ``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
+ * 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 BinaryPropertyList_h
+#define BinaryPropertyList_h
+
+#include &lt;wtf/Vector.h&gt;
+
+namespace WebCore {
+
+class String;
+
+// Writes a limited subset of binary property lists.
+// Covers only what's needed for writing browser history as of this writing.
+class BinaryPropertyListObjectStream {
+public:
+    // Call writeBooleanTrue to write the boolean true value.
+    // A single shared object will be used in the serialized list.
+    virtual void writeBooleanTrue() = 0;
+
+    // Call writeInteger to write an integer value.
+    // A single shared object will be used for each integer in the serialized list.
+    virtual void writeInteger(int) = 0;
+
+    // Call writeUniqueString to write a string value.
+    // A single shared object will be used for each string in the serialized list.
+    virtual void writeString(const String&amp;) = 0;
+
+    // Call writeUniqueString instead of writeString when it's unlikely the
+    // string will be written twice in the same property list; this saves hash
+    // table overhead for such strings. A separate object will be used for each
+    // of these strings in the serialized list.
+    virtual void writeUniqueString(const String&amp;) = 0;
+    virtual void writeUniqueString(const char*) = 0;
+
+    // Call writeIntegerArray instead of writeArrayStart/writeArrayEnd for
+    // arrays entirely composed of integers. A single shared object will be used
+    // for each identical array in the serialized list. Warning: The integer
+    // pointer must remain valid until the writeBinaryPropertyList function
+    // returns, because these lists are put into a hash table without copying
+    // them -- that's OK if the client already has a Vector&lt;int&gt;.
+    virtual void writeIntegerArray(const int*, size_t) = 0;
+
+    // After calling writeArrayStart, write array elements.
+    // Then call writeArrayEnd, passing in the result from writeArrayStart.
+    // A separate object will be used for each of these arrays in the serialized list.
+    virtual size_t writeArrayStart() = 0;
+    virtual void writeArrayEnd(size_t resultFromWriteArrayStart) = 0;
+
+    // After calling writeDictionaryStart, write all keys, then all values.
+    // Then call writeDictionaryEnd, passing in the result from writeDictionaryStart.
+    // A separate object will be used for each dictionary in the serialized list.
+    virtual size_t writeDictionaryStart() = 0;
+    virtual void writeDictionaryEnd(size_t resultFromWriteDictionaryStart) = 0;
+
+protected:
+    virtual ~BinaryPropertyListObjectStream() { }
+};
+
+class BinaryPropertyListWriter {
+public:
+    // Calls writeToStream once to prepare for writing and determine how big a
+    // buffer is required. Then calls buffer to get the appropriately-sized
+    // buffer, then calls writeToStream a second time and writes the property list.
+    void writePropertyList();
+
+protected:
+    virtual ~BinaryPropertyListWriter() { }
+
+private:
+    // Called by writePropertyList.
+    // Must call the object stream functions for the objects to be written
+    // into the property list.
+    virtual void writeObjects(BinaryPropertyListObjectStream&amp;) = 0;
+
+    // Called by writePropertyList.
+    // Returns the buffer that the writer should write into.
+    virtual UInt8* buffer(size_t) = 0;
+
+    friend class BinaryPropertyListPlan;
+    friend class BinaryPropertyListSerializer;
+};
+
+}
+
+#endif
</ins><span class="cx">Property changes on: trunk/WebCore/platform/cf/BinaryPropertyList.h
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svneolstyle"></a>
<div class="addfile"><h4>Added: svn:eol-style</h4></div>
<a id="trunkWebKitmacChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/WebKit/mac/ChangeLog (42371 => 42372)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebKit/mac/ChangeLog        2009-04-09 22:25:29 UTC (rev 42371)
+++ trunk/WebKit/mac/ChangeLog        2009-04-09 22:40:05 UTC (rev 42372)
</span><span class="lines">@@ -1,3 +1,22 @@
</span><ins>+2009-04-09  Darin Adler  &lt;darin@apple.com&gt;
+
+        Reviewed by Anders Carlsson and Sam Weinig.
+
+        Part of &lt;rdar://problem/5438063&gt; Saving history containing 100,000 entries causes pauses of 2s while browsing
+
+        Longer term solution is to change the design so Safari doesn't read and write all of history.
+        This patch is step one: Do the serializing, which is done on the main thread, much faster.
+
+        * History/WebHistory.mm:
+        (-[WebHistoryPrivate data]): Added. Returns the NSData object containing serialized history.
+        For creating new SPI so you can get the data in memory instead of on disk. Uses WebHistoryWriter.
+        (-[WebHistoryPrivate saveToURL:error:]): Changed to call [self data
+        (-[WebHistory _data]): Added.
+        (WebHistoryWriter::WebHistoryWriter): Added.
+        (WebHistoryWriter::writeHistoryItems): Added.
+
+        * History/WebHistoryPrivate.h: Added a new _data method.
+
</ins><span class="cx"> 2009-04-09  Mike Thole  &lt;mthole@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Rubber-stamped by Mark Rowe.
</span></span></pre></div>
<a id="trunkWebKitmacHistoryWebHistorymm"></a>
<div class="modfile"><h4>Modified: trunk/WebKit/mac/History/WebHistory.mm (42371 => 42372)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebKit/mac/History/WebHistory.mm        2009-04-09 22:25:29 UTC (rev 42371)
+++ trunk/WebKit/mac/History/WebHistory.mm        2009-04-09 22:40:05 UTC (rev 42372)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2005, 2008 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2005, 2008, 2009 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -33,9 +33,11 @@
</span><span class="cx"> #import &quot;WebNSURLExtras.h&quot;
</span><span class="cx"> #import &quot;WebTypesInternal.h&quot;
</span><span class="cx"> #import &lt;WebCore/HistoryItem.h&gt;
</span><ins>+#import &lt;WebCore/HistoryPropertyList.h&gt;
</ins><span class="cx"> #import &lt;WebCore/PageGroup.h&gt;
</span><span class="cx"> 
</span><span class="cx"> using namespace WebCore;
</span><ins>+using namespace std;
</ins><span class="cx"> 
</span><span class="cx"> typedef int64_t WebHistoryDateKey;
</span><span class="cx"> typedef HashMap&lt;WebHistoryDateKey, RetainPtr&lt;NSMutableArray&gt; &gt; DateToEntriesMap;
</span><span class="lines">@@ -55,6 +57,17 @@
</span><span class="cx"> 
</span><span class="cx"> #define currentFileVersion 1
</span><span class="cx"> 
</span><ins>+class WebHistoryWriter : public HistoryPropertyListWriter {
+public:
+    WebHistoryWriter(DateToEntriesMap*);
+
+private:
+    virtual void writeHistoryItems(BinaryPropertyListObjectStream&amp;);
+
+    DateToEntriesMap* m_entriesByDate;
+    Vector&lt;int&gt; m_dateKeys;
+};
+
</ins><span class="cx"> @interface WebHistoryPrivate : NSObject {
</span><span class="cx"> @private
</span><span class="cx">     NSMutableDictionary *_entriesByURL;
</span><span class="lines">@@ -382,7 +395,7 @@
</span><span class="cx">         for (DateToEntriesMap::const_iterator it = _entriesByDate-&gt;begin(); it != end; ++it)
</span><span class="cx">             daysAsTimeIntervals.append(it-&gt;first);
</span><span class="cx"> 
</span><del>-        std::sort(daysAsTimeIntervals.begin(), daysAsTimeIntervals.end());
</del><ins>+        sort(daysAsTimeIntervals.begin(), daysAsTimeIntervals.end());
</ins><span class="cx">         size_t count = daysAsTimeIntervals.size();
</span><span class="cx">         _orderedLastVisitedDays = [[NSMutableArray alloc] initWithCapacity:count];
</span><span class="cx">         for (int i = count - 1; i &gt;= 0; i--) {
</span><span class="lines">@@ -461,30 +474,6 @@
</span><span class="cx">                                                       hours:0 minutes:0 seconds:0];
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-// Return a flat array of WebHistoryItems. Ignores the date and item count limits; these are
-// respected when loading instead of when saving, so that clients can learn of discarded items
-// by listening to WebHistoryItemsDiscardedWhileLoadingNotification.
-- (NSArray *)arrayRepresentation
-{
-    NSMutableArray *arrayRep = [NSMutableArray array];
-
-    Vector&lt;int&gt; dateKeys;
-    dateKeys.reserveCapacity(_entriesByDate-&gt;size());
-    DateToEntriesMap::const_iterator end = _entriesByDate-&gt;end();
-    for (DateToEntriesMap::const_iterator it = _entriesByDate-&gt;begin(); it != end; ++it)
-        dateKeys.append(it-&gt;first);
-
-    std::sort(dateKeys.begin(), dateKeys.end());
-    for (int dateIndex = dateKeys.size() - 1; dateIndex &gt;= 0; dateIndex--) {
-        NSArray *entries = _entriesByDate-&gt;get(dateKeys[dateIndex]).get();
-        int entryCount = [entries count];
-        for (int entryIndex = 0; entryIndex &lt; entryCount; ++entryIndex)
-            [arrayRep addObject:[[entries objectAtIndex:entryIndex] dictionaryRepresentation]];
-    }
-
-    return arrayRep;
-}
-
</del><span class="cx"> - (BOOL)loadHistoryGutsFromURL:(NSURL *)URL savedItemsCount:(int *)numberOfItemsLoaded collectDiscardedItemsInto:(NSMutableArray *)discardedItems error:(NSError **)error
</span><span class="cx"> {
</span><span class="cx">     *numberOfItemsLoaded = 0;
</span><span class="lines">@@ -590,23 +579,13 @@
</span><span class="cx">     return YES;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-- (BOOL)saveHistoryGuts:(int *)numberOfItemsSaved URL:(NSURL *)URL error:(NSError **)error
</del><ins>+- (NSData *)data
</ins><span class="cx"> {
</span><del>-    *numberOfItemsSaved = 0;
-
-    NSArray *array = [self arrayRepresentation];
-    NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:
-        array, DatesArrayKey,
-        [NSNumber numberWithInt:currentFileVersion], FileVersionKey,
-        nil];
-    NSData *data = [NSPropertyListSerialization dataFromPropertyList:dictionary format:NSPropertyListBinaryFormat_v1_0 errorDescription:nil];
-    if (![data writeToURL:URL options:0 error:error]) {
-        LOG_ERROR(&quot;attempt to save %@ to %@ failed&quot;, dictionary, URL);
-        return NO;
-    }
-
-    *numberOfItemsSaved = [array count];
-    return YES;
</del><ins>+    // Ignores the date and item count limits; these are respected when loading instead of when saving, so
+    // that clients can learn of discarded items by listening to WebHistoryItemsDiscardedWhileLoadingNotification.
+    WebHistoryWriter writer(_entriesByDate);
+    writer.writePropertyList();
+    return [[(NSData *)writer.releaseData().get() retain] autorelease];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (BOOL)saveToURL:(NSURL *)URL error:(NSError **)error
</span><span class="lines">@@ -615,16 +594,14 @@
</span><span class="cx">     double start = CFAbsoluteTimeGetCurrent();
</span><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    int numberOfItems;
-    if (![self saveHistoryGuts:&amp;numberOfItems URL:URL error:error])
-        return NO;
</del><ins>+    BOOL result = [[self data] writeToURL:URL options:0 error:error];
</ins><span class="cx"> 
</span><span class="cx"> #if !LOG_DISABLED
</span><span class="cx">     double duration = CFAbsoluteTimeGetCurrent() - start;
</span><del>-    LOG(Timing, &quot;saving %d history entries to %@ took %f seconds&quot;, numberOfItems, URL, duration);
</del><ins>+    LOG(Timing, &quot;saving history to %@ took %f seconds&quot;, URL, duration);
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><del>-    return YES;
</del><ins>+    return result;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (void)addVisitedLinksToPageGroup:(PageGroup&amp;)group
</span><span class="lines">@@ -799,6 +776,11 @@
</span><span class="cx">     return [_historyPrivate allItems];
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+- (NSData *)_data
+{
+    return [_historyPrivate data];
+}
+
</ins><span class="cx"> @end
</span><span class="cx"> 
</span><span class="cx"> @implementation WebHistory (WebInternal)
</span><span class="lines">@@ -813,7 +795,7 @@
</span><span class="cx">     if ([method length])
</span><span class="cx">         item-&gt;setLastVisitWasHTTPNonGet([method caseInsensitiveCompare:@&quot;GET&quot;] &amp;&amp; (![[url scheme] caseInsensitiveCompare:@&quot;http&quot;] || ![[url scheme] caseInsensitiveCompare:@&quot;https&quot;]));
</span><span class="cx"> 
</span><del>-    item-&gt;setRedirectURLs(std::auto_ptr&lt;Vector&lt;String&gt; &gt;());
</del><ins>+    item-&gt;setRedirectURLs(auto_ptr&lt;Vector&lt;String&gt; &gt;());
</ins><span class="cx"> 
</span><span class="cx">     NSArray *entries = [[NSArray alloc] initWithObjects:entry, nil];
</span><span class="cx">     [self _sendNotification:WebHistoryItemsAddedNotification entries:entries];
</span><span class="lines">@@ -826,3 +808,23 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> @end
</span><ins>+
+WebHistoryWriter::WebHistoryWriter(DateToEntriesMap* entriesByDate)
+    : m_entriesByDate(entriesByDate)
+{
+    m_dateKeys.reserveCapacity(m_entriesByDate-&gt;size());
+    DateToEntriesMap::const_iterator end = m_entriesByDate-&gt;end();
+    for (DateToEntriesMap::const_iterator it = m_entriesByDate-&gt;begin(); it != end; ++it)
+        m_dateKeys.append(it-&gt;first);
+    sort(m_dateKeys.begin(), m_dateKeys.end());
+}
+
+void WebHistoryWriter::writeHistoryItems(BinaryPropertyListObjectStream&amp; stream)
+{
+    for (int dateIndex = m_dateKeys.size() - 1; dateIndex &gt;= 0; dateIndex--) {
+        NSArray *entries = m_entriesByDate-&gt;get(m_dateKeys[dateIndex]).get();
+        NSUInteger entryCount = [entries count];
+        for (NSUInteger entryIndex = 0; entryIndex &lt; entryCount; ++entryIndex)
+            writeHistoryItem(stream, core([entries objectAtIndex:entryIndex]));
+    }
+}
</ins></span></pre></div>
<a id="trunkWebKitmacHistoryWebHistoryPrivateh"></a>
<div class="modfile"><h4>Modified: trunk/WebKit/mac/History/WebHistoryPrivate.h (42371 => 42372)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/WebKit/mac/History/WebHistoryPrivate.h        2009-04-09 22:25:29 UTC (rev 42371)
+++ trunk/WebKit/mac/History/WebHistoryPrivate.h        2009-04-09 22:40:05 UTC (rev 42372)
</span><span class="lines">@@ -1,5 +1,5 @@
</span><span class="cx"> /*
</span><del>- * Copyright (C) 2005, 2008 Apple Inc. All rights reserved.
</del><ins>+ * Copyright (C) 2005, 2008, 2009 Apple Inc. All rights reserved.
</ins><span class="cx">  *
</span><span class="cx">  * Redistribution and use in source and binary forms, with or without
</span><span class="cx">  * modification, are permitted provided that the following conditions
</span><span class="lines">@@ -47,4 +47,11 @@
</span><span class="cx"> */
</span><span class="cx"> - (NSArray *)allItems;
</span><span class="cx"> 
</span><ins>+/*!
+    @method _data
+    @result A data object with the entire history in the same format used by the saveToURL:error: method.
+*/
+- (NSData *)_data;
+
+
</ins><span class="cx"> @end
</span></span></pre>
</div>
</div>

</body>
</html>